diff --git a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-devel.yml b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-devel.yml index 63feb83..908a4a7 100644 --- a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-devel.yml +++ b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-devel.yml @@ -30,7 +30,7 @@ objects: failedJobsHistoryLimit: 2 jobTemplate: spec: - activeDeadlineSeconds: 2400 # Can run for 40 minutes + activeDeadlineSeconds: 5400 # Can run for 90 minutes template: spec: restartPolicy: Never diff --git a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-production.yml b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-production.yml index 84c9733..0dc112e 100644 --- a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-production.yml +++ b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-production.yml @@ -30,7 +30,7 @@ objects: failedJobsHistoryLimit: 2 jobTemplate: spec: - activeDeadlineSeconds: 2400 # Can run for 40 minutes + activeDeadlineSeconds: 5400 # Can run for 90 minutes template: spec: restartPolicy: Never diff --git a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-qa.yml b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-qa.yml index 5d124ae..d3ff438 100644 --- a/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-qa.yml +++ b/aspnetcore/openshift/indexer/rahti2/template-indexer-cronjob-qa.yml @@ -30,7 +30,7 @@ objects: failedJobsHistoryLimit: 2 jobTemplate: spec: - activeDeadlineSeconds: 2400 # Can run for 40 minutes + activeDeadlineSeconds: 5400 # Can run for 90 minutes template: spec: restartPolicy: Never diff --git a/aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs b/aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs index c0bd9ea..73203d2 100644 --- a/aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs +++ b/aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs @@ -6,7 +6,7 @@ namespace ResearchFi.Query; /// Query parameters for searching funding calls. /// /// -public class GetFundingCallQueryParameters : PaginationQueryParameters +public class GetFundingCallQueryParameters { /// /// One of the fields nameFi, nameSV, nameEn contains the full text. diff --git a/aspnetcore/src/ApiModels/Query/GetFundingDecisionQueryParameters.cs b/aspnetcore/src/ApiModels/Query/GetFundingDecisionQueryParameters.cs index 2213ae0..18c3f0c 100644 --- a/aspnetcore/src/ApiModels/Query/GetFundingDecisionQueryParameters.cs +++ b/aspnetcore/src/ApiModels/Query/GetFundingDecisionQueryParameters.cs @@ -6,7 +6,7 @@ namespace ResearchFi.Query; /// Query parameters for searching funding decisions. /// /// -public class GetFundingDecisionQueryParameters : PaginationQueryParameters +public class GetFundingDecisionQueryParameters { /// /// One of the fields nameFi, nameSV, nameEn contains the full text. diff --git a/aspnetcore/src/ApiModels/Query/GetInfrastructuresQueryParameters.cs b/aspnetcore/src/ApiModels/Query/GetInfrastructuresQueryParameters.cs index 0e9afbf..a29000e 100644 --- a/aspnetcore/src/ApiModels/Query/GetInfrastructuresQueryParameters.cs +++ b/aspnetcore/src/ApiModels/Query/GetInfrastructuresQueryParameters.cs @@ -3,7 +3,7 @@ /// /// Hakuparametrit infrastruktuurien hakemiseen. /// -public class GetInfrastructuresQueryParameters : PaginationQueryParameters +public class GetInfrastructuresQueryParameters { /// /// Infrastruktuurin nimi. diff --git a/aspnetcore/src/ApiModels/Query/GetPublicationsQueryParameters.cs b/aspnetcore/src/ApiModels/Query/GetPublicationsQueryParameters.cs index 48e46c1..d170712 100644 --- a/aspnetcore/src/ApiModels/Query/GetPublicationsQueryParameters.cs +++ b/aspnetcore/src/ApiModels/Query/GetPublicationsQueryParameters.cs @@ -6,7 +6,7 @@ namespace ResearchFi.Query; /// Query parameters for searching publications. /// /// -public class GetPublicationsQueryParameters : PaginationQueryParameters +public class GetPublicationsQueryParameters { /// /// The field name contains text. diff --git a/aspnetcore/src/ApiModels/Query/PaginationQueryParameters.cs b/aspnetcore/src/ApiModels/Query/PaginationQueryParameters.cs index 8fbd10c..cbd8742 100644 --- a/aspnetcore/src/ApiModels/Query/PaginationQueryParameters.cs +++ b/aspnetcore/src/ApiModels/Query/PaginationQueryParameters.cs @@ -19,7 +19,7 @@ public int PageNumber } /// - /// Number of results on page. Optional. Default value 20. Maximum permissible value 100. Maximum possible result set of 10,000 results. + /// Number of results on page. Optional. Default value 20. Maximum permissible value 100. Maximum possible result set of 10000 results. /// public int PageSize { diff --git a/aspnetcore/src/ApiModels/Query/SearchAfterQueryParameters.cs b/aspnetcore/src/ApiModels/Query/SearchAfterQueryParameters.cs new file mode 100644 index 0000000..9ca8fab --- /dev/null +++ b/aspnetcore/src/ApiModels/Query/SearchAfterQueryParameters.cs @@ -0,0 +1,30 @@ +namespace ResearchFi.Query; + +/// +/// Vientiin liittyvät tiedot. +/// +public class SearchAfterQueryParameters +{ + private const int DefaultPageSize = 50; + private const int MaximumPageSize = 1000; + private int _pageSize = DefaultPageSize; + private long? _nextPageToken = null; + + /// + /// Number of results on page. Optional. Default value 50. Maximum permissible value 1000. + /// + public int PageSize + { + get => _pageSize; + set => _pageSize = value < 1 ? DefaultPageSize : (value > MaximumPageSize ? MaximumPageSize : value); + } + + /// + /// Value from previous query response header "x-next-page-token". Leave empty in the first query. + /// + public long? NextPageToken + { + get => _nextPageToken; + set => _nextPageToken = value; + } +} \ No newline at end of file diff --git a/aspnetcore/src/ElasticService/ElasticSearchIndexService.cs b/aspnetcore/src/ElasticService/ElasticSearchIndexService.cs index d1d0d01..0ff095f 100644 --- a/aspnetcore/src/ElasticService/ElasticSearchIndexService.cs +++ b/aspnetcore/src/ElasticService/ElasticSearchIndexService.cs @@ -32,7 +32,7 @@ public async Task IndexAsync(string indexName, List entities, Type model await IndexEntities(indexToCreate, entities, modelType); // Switch indexes - await SwitchIndexes(indexName, indexToCreate, indexToDelete); + await SwitchIndexes(indexName, indexToCreate, indexToDelete, modelType.Name); _logger.LogDebug("{EntityType:l}: Indexing to {IndexName:l} complete", modelType.Name, indexName); } @@ -43,8 +43,9 @@ public async Task IndexChunkAsync(string indexToCreate, List entities, T await IndexEntities(indexToCreate, entities, modelType); } - public async Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete) + public async Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete, string modelTypeName) { + _logger.LogInformation($"{modelTypeName}: Switch indexes start: indexName={indexName}, indexToCreate={indexToCreate}, indexToDelete={indexToDelete}"); // Wait for new index to be operational. await _elasticClient.Cluster .HealthAsync(selector: s => s @@ -61,6 +62,7 @@ await _elasticClient.Indices.BulkAliasAsync(r => r // Delete the old index if it exists. await _elasticClient.Indices.DeleteAsync(indexToDelete, d => d.RequestConfiguration(x => x.AllowedStatusCodes(404))); + _logger.LogInformation($"{modelTypeName}: Switch indexes complete"); } public async Task<(string indexToCreate, string indexToDelete)> GetIndexNames(string indexName) diff --git a/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/IQueryGenerator.cs b/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/IQueryGenerator.cs index 701cf3b..e39a5d7 100644 --- a/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/IQueryGenerator.cs +++ b/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/IQueryGenerator.cs @@ -5,5 +5,6 @@ namespace CSC.PublicApi.ElasticService.ElasticSearchQueryGenerators; public interface IQueryGenerator where TOut : class { Func, ISearchRequest> GenerateQuery(TIn searchParameters, int pageNumber, int pageSize); + Func, ISearchRequest> GenerateQuerySearchAfter(TIn searchParameters, int pageSize, long? searchAfter); Func, ISearchRequest> GenerateSingleQuery(string id); } \ No newline at end of file diff --git a/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/QueryGeneratorBase.cs b/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/QueryGeneratorBase.cs index 8afc1a8..ffb31d7 100644 --- a/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/QueryGeneratorBase.cs +++ b/aspnetcore/src/ElasticService/ElasticSearchQueryGenerators/QueryGeneratorBase.cs @@ -22,6 +22,27 @@ public Func, ISearchRequest> GenerateQuery(TIn searchPara .Query(GenerateQueryForSearch(searchParameters)); } + public Func, ISearchRequest> GenerateQuerySearchAfter(TIn searchParameters, int pageSize, long? searchAfter) + { + var indexName = _configuration.GetIndexNameForType(typeof(TOut)); + + if (searchAfter == null) { + return descriptor => descriptor + .Index(indexName) + .Take(pageSize) + .Sort(sort => sort.Ascending(SortSpecialField.DocumentIndexOrder)) + .Query(GenerateQueryForSearch(searchParameters)); + } + else { + return descriptor => descriptor + .Index(indexName) + .Take(pageSize) + .Sort(sort => sort.Ascending(SortSpecialField.DocumentIndexOrder)) + .Query(GenerateQueryForSearch(searchParameters)) + .SearchAfter(searchAfter); + } + } + public Func, ISearchRequest> GenerateSingleQuery(string id) { var indexName = _configuration.GetIndexNameForType(typeof(TOut)); diff --git a/aspnetcore/src/ElasticService/ElasticSearchService.cs b/aspnetcore/src/ElasticService/ElasticSearchService.cs index 7193d7e..b5d3f58 100644 --- a/aspnetcore/src/ElasticService/ElasticSearchService.cs +++ b/aspnetcore/src/ElasticService/ElasticSearchService.cs @@ -32,6 +32,27 @@ public ElasticSearchService( return (searchResult.Documents, new SearchResult(pageNumber, pageSize, searchResult.HitsMetadata?.Total.Value)); } + public async Task<(IEnumerable, SearchAfterResult)> SearchAfter(TIn parameters, int pageSize, long? searchAfter) + { + var query = _queryGenerator.GenerateQuerySearchAfter(parameters, pageSize, searchAfter); + + var searchResult = await _elasticClient.SearchAsync(query); + + if (Debugger.IsAttached) + { + // Enables seeing the query sent to elastic and the response in the log when debugging. + Console.WriteLine(searchResult.DebugInformation); + } + + long? searchAfterValue = null; + + if (searchResult.Hits.Count > 0) { + searchAfterValue = (long)searchResult.Hits.Last().Sorts.First(); + } + + return (searchResult.Documents, new SearchAfterResult(searchAfterValue, pageSize)); + } + public async Task GetSingle(string id) { var query = _queryGenerator.GenerateSingleQuery(id); diff --git a/aspnetcore/src/ElasticService/IElasticSearchIndexService.cs b/aspnetcore/src/ElasticService/IElasticSearchIndexService.cs index 960b848..f949344 100644 --- a/aspnetcore/src/ElasticService/IElasticSearchIndexService.cs +++ b/aspnetcore/src/ElasticService/IElasticSearchIndexService.cs @@ -48,6 +48,7 @@ public interface IElasticSearchIndexService /// /// /// + /// /// - Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete); + Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete, string modelTypeName); } \ No newline at end of file diff --git a/aspnetcore/src/ElasticService/ISearchService.cs b/aspnetcore/src/ElasticService/ISearchService.cs index 5242e1e..43992b8 100644 --- a/aspnetcore/src/ElasticService/ISearchService.cs +++ b/aspnetcore/src/ElasticService/ISearchService.cs @@ -3,6 +3,6 @@ public interface ISearchService where TOut : class { Task<(IEnumerable, SearchResult)> Search(TIn searchParameters, int pageNumber, int pageSize); - + Task<(IEnumerable, SearchAfterResult)> SearchAfter(TIn searchParameters, int pageSize, long? searchAfter); Task GetSingle(string id); } \ No newline at end of file diff --git a/aspnetcore/src/ElasticService/SearchAfterResult.cs b/aspnetcore/src/ElasticService/SearchAfterResult.cs new file mode 100644 index 0000000..5fa6a51 --- /dev/null +++ b/aspnetcore/src/ElasticService/SearchAfterResult.cs @@ -0,0 +1,12 @@ +namespace CSC.PublicApi.ElasticService; + +public class SearchAfterResult +{ + public long? SearchAfter { get; } + public int PageSize { get; } + public SearchAfterResult(long? searchAfter, int pageSize) + { + SearchAfter = searchAfter; + PageSize = pageSize; + } +} \ No newline at end of file diff --git a/aspnetcore/src/Indexer/Indexer.cs b/aspnetcore/src/Indexer/Indexer.cs index 5c8ed9c..7da2a99 100644 --- a/aspnetcore/src/Indexer/Indexer.cs +++ b/aspnetcore/src/Indexer/Indexer.cs @@ -177,7 +177,7 @@ private async Task IndexEntities(string indexName, IIndexRepository repository, } while (numOfResults >= takeAmount - 1); // Activate new index and delete old - await _indexService.SwitchIndexes(indexName, indexToCreate, indexToDelete); + await _indexService.SwitchIndexes(indexName, indexToCreate, indexToDelete, type.Name); _logger.LogInformation("{EntityType:l}: Recreated index {IndexName:l}, {ElasticsearchDocumentCount} documents", type.Name, indexName, processedCount); } else diff --git a/aspnetcore/src/Interface/Configuration/SwaggerExtensions.cs b/aspnetcore/src/Interface/Configuration/SwaggerExtensions.cs index 3ca855e..c841237 100644 --- a/aspnetcore/src/Interface/Configuration/SwaggerExtensions.cs +++ b/aspnetcore/src/Interface/Configuration/SwaggerExtensions.cs @@ -76,6 +76,7 @@ public static void UseSwaggerAndSwaggerUI(this WebApplication app) foreach (var description in app.Services.GetRequiredService().ApiVersionDescriptions) { options.SwaggerEndpoint($"{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); + options.ConfigObject.AdditionalItems.Add("syntaxHighlight", false); // disable to improve performance with large responses } }); } diff --git a/aspnetcore/src/Interface/Controllers/FundingCallController.cs b/aspnetcore/src/Interface/Controllers/FundingCallController.cs index c3da5b9..f9621e7 100644 --- a/aspnetcore/src/Interface/Controllers/FundingCallController.cs +++ b/aspnetcore/src/Interface/Controllers/FundingCallController.cs @@ -30,7 +30,7 @@ public FundingCallController( /// /// Endpoint for filtering funding calls using the specified query parameters. /// - /// The query parameters for filtering the results. + /// The query parameters for filtering the results. /// Paged search result as a collection of objects. /// Ok. /// Unauthorized. @@ -43,9 +43,9 @@ public FundingCallController( [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] - public async Task> Get([FromQuery] GetFundingCallQueryParameters queryParameters) + public async Task> Get([FromQuery] GetFundingCallQueryParameters fundingCallQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (fundingCalls, searchResult) = await _service.GetFundingCalls(queryParameters); + var (fundingCalls, searchResult) = await _service.GetFundingCalls(fundingCallQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); diff --git a/aspnetcore/src/Interface/Controllers/FundingCallExportController.cs b/aspnetcore/src/Interface/Controllers/FundingCallExportController.cs new file mode 100644 index 0000000..6753875 --- /dev/null +++ b/aspnetcore/src/Interface/Controllers/FundingCallExportController.cs @@ -0,0 +1,54 @@ +using CSC.PublicApi.Interface.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ResearchFi.FundingCall; +using ResearchFi.Query; +using Serilog; + +namespace CSC.PublicApi.Interface.Controllers; + +[ApiController] +[ApiVersion(ApiConstants.ApiVersion1)] +[Route("v{version:apiVersion}/funding-calls-export")] +public class FundingCallExportController : ControllerBase +{ + private readonly ILogger _logger; + private readonly IFundingCallService _service; + private readonly IDiagnosticContext _diagnosticContext; + + public FundingCallExportController( + ILogger logger, + IFundingCallService service, + IDiagnosticContext diagnosticContext) + { + _logger = logger; + _service = service; + _diagnosticContext = diagnosticContext; + _diagnosticContext.Set(ApiConstants.LogResourceType_PropertyName, ApiConstants.LogResourceType_FundingCall); + } + + /// + /// Endpoint for bypassing the limit of 10000 records for funding calls. + /// + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetFundingCallExport")] + [MapToApiVersion(ApiConstants.ApiVersion1)] + [Authorize(Policy = ApiPolicies.FundingCall.Read)] + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] + public async Task> Get([FromQuery] GetFundingCallQueryParameters fundingCallQueryParameters, [FromQuery] SearchAfterQueryParameters searchAfterQueryParameters) + { + var (fundingCalls, searchAfterResult) = await _service.GetFundingCallsSearchAfter(fundingCallQueryParameters, searchAfterQueryParameters); + + ResponseHelper.AddPaginationResponseHeadersSearchAfter(HttpContext, searchAfterResult); + + return fundingCalls; + } +} \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/FundingDecisionController.cs b/aspnetcore/src/Interface/Controllers/FundingDecisionController.cs index 1f250a3..cad980b 100644 --- a/aspnetcore/src/Interface/Controllers/FundingDecisionController.cs +++ b/aspnetcore/src/Interface/Controllers/FundingDecisionController.cs @@ -32,6 +32,7 @@ public FundingDecisionController( /// /// Endpoint for filtering funding decisions using the specified query parameters. /// + /// The query parameters for filtering the results. /// Paged search result as a collection of objects. /// Ok. /// Unauthorized. @@ -44,9 +45,9 @@ public FundingDecisionController( [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] - public async Task> Get([FromQuery] GetFundingDecisionQueryParameters queryParameters) + public async Task> Get([FromQuery] GetFundingDecisionQueryParameters fundingDecisionQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (fundingDecisions, searchResult) = await _service.GetFundingDecisions(queryParameters); + var (fundingDecisions, searchResult) = await _service.GetFundingDecisions(fundingDecisionQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); diff --git a/aspnetcore/src/Interface/Controllers/FundingDecisionExportController.cs b/aspnetcore/src/Interface/Controllers/FundingDecisionExportController.cs new file mode 100644 index 0000000..798c1a2 --- /dev/null +++ b/aspnetcore/src/Interface/Controllers/FundingDecisionExportController.cs @@ -0,0 +1,56 @@ +using CSC.PublicApi.Interface.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ResearchFi.FundingDecision; +using ResearchFi.Query; +using Serilog; + +namespace CSC.PublicApi.Interface.Controllers; + +[ApiController] +[ApiVersion(ApiVersion)] +[Route("v{version:apiVersion}/funding-decisions-export")] + +public class FundingDecisionExportController : ControllerBase +{ + private const string ApiVersion = "1.0"; + private readonly ILogger _logger; + private readonly IFundingDecisionService _service; + private readonly IDiagnosticContext _diagnosticContext; + + public FundingDecisionExportController( + ILogger logger, + IFundingDecisionService service, + IDiagnosticContext diagnosticContext) + { + _logger = logger; + _service = service; + _diagnosticContext = diagnosticContext; + _diagnosticContext.Set(ApiConstants.LogResourceType_PropertyName, ApiConstants.LogResourceType_FundingDecision); + } + + /// + /// Endpoint for bypassing the limit of 10000 records for funding decisions. + /// + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetFundingDecisionExport")] + [MapToApiVersion(ApiVersion)] + [Authorize(Policy = ApiPolicies.FundingDecision.Read)] + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] + public async Task> Get([FromQuery] GetFundingDecisionQueryParameters fundingDecisionQueryParameters, [FromQuery] SearchAfterQueryParameters searchAfterQueryParameters) + { + var (fundingDecisions, searchAfterResult) = await _service.GetFundingDecisionsSearchAfter(fundingDecisionQueryParameters, searchAfterQueryParameters); + + ResponseHelper.AddPaginationResponseHeadersSearchAfter(HttpContext, searchAfterResult); + + return fundingDecisions; + } +} \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/InfrastructureController.cs b/aspnetcore/src/Interface/Controllers/InfrastructureController.cs index d228721..122fc3a 100644 --- a/aspnetcore/src/Interface/Controllers/InfrastructureController.cs +++ b/aspnetcore/src/Interface/Controllers/InfrastructureController.cs @@ -32,17 +32,26 @@ public InfrastructureController( /// /// Search Infrastructures /// - /// Query parameters for filtering the results. - /// - /*[HttpGet(Name = "GetInfrastructure")] + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetInfrastructure")] [MapToApiVersion(ApiVersion)] [Authorize(Policy = ApiPolicies.Infrastructure.Read)] - public async Task> Get([FromQuery] GetInfrastructuresQueryParameters queryParameters) + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] + [ApiExplorerSettings(IgnoreApi = true)] // Hidden + public async Task> Get([FromQuery] GetInfrastructuresQueryParameters infrastructuresQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (infrastructures, searchResult) = await _service.GetInfrastructures(queryParameters); + var (infrastructures, searchResult) = await _service.GetInfrastructures(infrastructuresQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); return infrastructures; - }*/ + } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/OrganizationController.cs b/aspnetcore/src/Interface/Controllers/OrganizationController.cs index 62025f6..513226a 100644 --- a/aspnetcore/src/Interface/Controllers/OrganizationController.cs +++ b/aspnetcore/src/Interface/Controllers/OrganizationController.cs @@ -32,17 +32,26 @@ public OrganizationController( /// /// Hae organisaatioita /// - /// - /// - /*[HttpGet(Name = "GetOrganization")] + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetOrganization")] [MapToApiVersion(ApiVersion)] [Authorize(Policy = ApiPolicies.Organization.Read)] - public async Task> Get([FromQuery] GetOrganizationsQueryParameters queryParameters) + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] + [ApiExplorerSettings(IgnoreApi = true)] // Hidden + public async Task> Get([FromQuery] GetOrganizationsQueryParameters organizationsQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (organizations, searchResult) = await _service.GetOrganizations(queryParameters); + var (organizations, searchResult) = await _service.GetOrganizations(organizationsQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); return organizations; - }*/ + } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/PublicationController.cs b/aspnetcore/src/Interface/Controllers/PublicationController.cs index baebcfe..d6cf501 100644 --- a/aspnetcore/src/Interface/Controllers/PublicationController.cs +++ b/aspnetcore/src/Interface/Controllers/PublicationController.cs @@ -31,20 +31,21 @@ public PublicationController( /// /// Endpoint for filtering publications using the specified query parameters. /// + /// The query parameters for filtering the results. /// Paged search result as a collection of objects. /// Ok. /// Unauthorized. /// Forbidden. - [HttpGet(Name = "SearchPublications")] + [HttpGet(Name = "GetPublications")] [Authorize(Policy = ApiPolicies.Publication.Read)] [Produces(ApiConstants.ContentTypeJson)] [Consumes(ApiConstants.ContentTypeJson)] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] - public async Task> Get([FromQuery] GetPublicationsQueryParameters queryParameters) + public async Task> Get([FromQuery] GetPublicationsQueryParameters publicationsQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (publications, searchResult) = await _service.GetPublications(queryParameters); + var (publications, searchResult) = await _service.GetPublications(publicationsQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); diff --git a/aspnetcore/src/Interface/Controllers/PublicationExportController.cs b/aspnetcore/src/Interface/Controllers/PublicationExportController.cs new file mode 100644 index 0000000..62c076f --- /dev/null +++ b/aspnetcore/src/Interface/Controllers/PublicationExportController.cs @@ -0,0 +1,54 @@ +using ResearchFi.Publication; +using CSC.PublicApi.Interface.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ResearchFi.Query; +using Serilog; + +namespace CSC.PublicApi.Interface.Controllers; + +[ApiController] +[ApiVersion(ApiConstants.ApiVersion1)] +[Route("v{version:apiVersion}/publications-export")] + +public class PublicationExportController : ControllerBase +{ + private readonly ILogger _logger; + private IPublicationService _service; + private readonly IDiagnosticContext _diagnosticContext; + + public PublicationExportController( + ILogger logger, + IPublicationService service, + IDiagnosticContext diagnosticContext) + { + _logger = logger; + _service = service; + _diagnosticContext = diagnosticContext; + _diagnosticContext.Set(ApiConstants.LogResourceType_PropertyName, ApiConstants.LogResourceType_Publication); + } + + /// + /// Endpoint for bypassing the limit of 10000 records for publications. + /// + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetPublicationsExport")] + [Authorize(Policy = ApiPolicies.Publication.Read)] + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void), StatusCodes.Status403Forbidden)] + public async Task> Get([FromQuery] GetPublicationsQueryParameters publicationsQueryParameters, [FromQuery] SearchAfterQueryParameters searchAfterQueryParameters) + { + var (publications, searchAfterResult) = await _service.GetPublicationsSearchAfter(publicationsQueryParameters, searchAfterQueryParameters); + + ResponseHelper.AddPaginationResponseHeadersSearchAfter(HttpContext, searchAfterResult); + + return publications; + } +} \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/ResearchDatasetController.cs b/aspnetcore/src/Interface/Controllers/ResearchDatasetController.cs index 02661b2..ca82403 100644 --- a/aspnetcore/src/Interface/Controllers/ResearchDatasetController.cs +++ b/aspnetcore/src/Interface/Controllers/ResearchDatasetController.cs @@ -32,6 +32,7 @@ public ResearchDatasetController( /// /// Endpoint for filtering research datasets using the specified query parameters. /// + /// The query parameters for filtering the results. /// Paged search result as a collection of objects. /// Ok. /// Unauthorized. @@ -44,9 +45,9 @@ public ResearchDatasetController( [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] - public async Task> Get([FromQuery] GetResearchDatasetsQueryParameters queryParameters) + public async Task> Get([FromQuery] GetResearchDatasetsQueryParameters researchDatasetsQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters) { - var (researchDatasets, searchResult) = await _service.GetResearchDatasets(queryParameters); + var (researchDatasets, searchResult) = await _service.GetResearchDatasets(researchDatasetsQueryParameters, paginationQueryParameters); ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult); diff --git a/aspnetcore/src/Interface/Controllers/ResearchDatasetExportController.cs b/aspnetcore/src/Interface/Controllers/ResearchDatasetExportController.cs new file mode 100644 index 0000000..7debb5c --- /dev/null +++ b/aspnetcore/src/Interface/Controllers/ResearchDatasetExportController.cs @@ -0,0 +1,56 @@ +using CSC.PublicApi.Interface.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using ResearchFi.Query; +using ResearchDataset = ResearchFi.ResearchDataset.ResearchDataset; +using Serilog; + +namespace CSC.PublicApi.Interface.Controllers; + +[ApiController] +[ApiVersion(ApiVersion)] +[Route("v{version:apiVersion}/research-datasets-export")] +public class ResearchDatasetExportController : ControllerBase +{ + private const string ApiVersion = "1.0"; + + private readonly ILogger _logger; + private IResearchDatasetService _service; + private readonly IDiagnosticContext _diagnosticContext; + + public ResearchDatasetExportController( + ILogger logger, + IResearchDatasetService service, + IDiagnosticContext diagnosticContext) + { + _logger = logger; + _service = service; + _diagnosticContext = diagnosticContext; + _diagnosticContext.Set(ApiConstants.LogResourceType_PropertyName, ApiConstants.LogResourceType_ResearchDataset); + } + + /// + /// Endpoint for bypassing the limit of 10000 records for research datasets. + /// + /// The query parameters for filtering the results. + /// Paged search result as a collection of objects. + /// Ok. + /// Unauthorized. + /// Forbidden. + [HttpGet(Name = "GetResearchDatasetExport")] + [MapToApiVersion(ApiVersion)] + [Authorize(Policy = ApiPolicies.ResearchDataset.Read)] + [Produces(ApiConstants.ContentTypeJson)] + [Consumes(ApiConstants.ContentTypeJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + [ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)] + public async Task> Get([FromQuery] GetResearchDatasetsQueryParameters researchDatasetsQueryParameters, [FromQuery] SearchAfterQueryParameters searchAfterQueryParameters) + { + var (researchDatasets, searchAfterResult) = await _service.GetResearchDatasetsSearchAfter(researchDatasetsQueryParameters, searchAfterQueryParameters); + + ResponseHelper.AddPaginationResponseHeadersSearchAfter(HttpContext, searchAfterResult); + + return researchDatasets; + } +} \ No newline at end of file diff --git a/aspnetcore/src/Interface/Controllers/ResponseHelper.cs b/aspnetcore/src/Interface/Controllers/ResponseHelper.cs index cd19204..87b4f81 100644 --- a/aspnetcore/src/Interface/Controllers/ResponseHelper.cs +++ b/aspnetcore/src/Interface/Controllers/ResponseHelper.cs @@ -25,33 +25,51 @@ public static void AddPaginationResponseHeaders(HttpContext httpContext, SearchR httpContext.Response.Headers.Add("link", GetLinks(httpContext.Request, results.PageNumber, results.TotalPages)); } + public static void AddPaginationResponseHeadersSearchAfter(HttpContext httpContext, SearchAfterResult searchAfterResult) + { + httpContext.Response.Headers.Add("x-page-size", searchAfterResult.PageSize.ToString()); + if (searchAfterResult.SearchAfter != null) + { + httpContext.Response.Headers.Add("x-next-page-token", searchAfterResult.SearchAfter.ToString()); + httpContext.Response.Headers.Add("link", GetLinksSearchAfter(httpContext.Request, searchAfterResult.SearchAfter)); + } + } + private static string GetLinks(HttpRequest httpRequest, int pageNumber, int totalPages) { var url = $"{httpRequest.Scheme}://{httpRequest.Host}{httpRequest.Path}"; - var queryValues = QueryHelpers.ParseQuery(httpRequest.QueryString.Value); - var result = string.Empty; - if (pageNumber < totalPages) { result += $"{CreateLink(url, queryValues, pageNumber + 1, Next)}, "; } - result += $"{CreateLink(url, queryValues, totalPages, Last)}, {CreateLink(url, queryValues, 1, First)}"; - if (pageNumber > 1) { result += $", {CreateLink(url, queryValues, pageNumber - 1, Previous)}"; } - + return result; + } + private static string GetLinksSearchAfter(HttpRequest httpRequest, long? searchAfter) + { + var url = $"{httpRequest.Scheme}://{httpRequest.Host}{httpRequest.Path}"; + var queryValues = QueryHelpers.ParseQuery(httpRequest.QueryString.Value); + var result = string.Empty; + if (searchAfter != null) { + result += $"{CreateLinkSearchAfter(url, queryValues, searchAfter, Next)}"; + } return result; } private static string CreateLink(string url, Dictionary query, int pageNumber, string rel) { query["pageNumber"] = pageNumber.ToString(); - + return $"<{QueryHelpers.AddQueryString(url, query)}>; rel=\"{rel}\""; + } + private static string CreateLinkSearchAfter(string url, Dictionary query, long? searchAfter, string rel) + { + query["NextPageToken"] = searchAfter.ToString(); return $"<{QueryHelpers.AddQueryString(url, query)}>; rel=\"{rel}\""; } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Interface.csproj b/aspnetcore/src/Interface/Interface.csproj index 7b028f6..dee5fe3 100644 --- a/aspnetcore/src/Interface/Interface.csproj +++ b/aspnetcore/src/Interface/Interface.csproj @@ -39,7 +39,7 @@ - + diff --git a/aspnetcore/src/Interface/Services/FundingCallService.cs b/aspnetcore/src/Interface/Services/FundingCallService.cs index 628f1e6..2df487a 100644 --- a/aspnetcore/src/Interface/Services/FundingCallService.cs +++ b/aspnetcore/src/Interface/Services/FundingCallService.cs @@ -21,15 +21,24 @@ public FundingCallService(ILogger logger, _searchService = searchService; } - public async Task<(IEnumerable, SearchResult)> GetFundingCalls(GetFundingCallQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetFundingCalls(GetFundingCallQueryParameters fundingCallQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(fundingCallQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + public async Task<(IEnumerable, SearchAfterResult)> GetFundingCallsSearchAfter(GetFundingCallQueryParameters fundingCallQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(fundingCallQueryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } + public async Task PostFundCall(FundingCall fundingCall) { // TODO: only NameFi mapped to entity. Not using final models yet. diff --git a/aspnetcore/src/Interface/Services/FundingDecisionService.cs b/aspnetcore/src/Interface/Services/FundingDecisionService.cs index 136e5bc..1851ddd 100644 --- a/aspnetcore/src/Interface/Services/FundingDecisionService.cs +++ b/aspnetcore/src/Interface/Services/FundingDecisionService.cs @@ -19,12 +19,21 @@ public FundingDecisionService(ILogger logger, IMapper ma _searchService = searchService; } - public async Task<(IEnumerable, SearchResult)> GetFundingDecisions(GetFundingDecisionQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetFundingDecisions(GetFundingDecisionQueryParameters fundingDecisionQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(fundingDecisionQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + + public async Task<(IEnumerable, SearchAfterResult)> GetFundingDecisionsSearchAfter(GetFundingDecisionQueryParameters fundingDecisionQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(fundingDecisionQueryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IFundingCallService.cs b/aspnetcore/src/Interface/Services/IFundingCallService.cs index 3974858..469bd45 100644 --- a/aspnetcore/src/Interface/Services/IFundingCallService.cs +++ b/aspnetcore/src/Interface/Services/IFundingCallService.cs @@ -6,6 +6,7 @@ namespace CSC.PublicApi.Interface.Services; public interface IFundingCallService { - Task<(IEnumerable, SearchResult)> GetFundingCalls(GetFundingCallQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetFundingCalls(GetFundingCallQueryParameters fundingCallQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetFundingCallsSearchAfter(GetFundingCallQueryParameters fundingCallQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); Task PostFundCall(FundingCall fundingCall); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IFundingDecisionService.cs b/aspnetcore/src/Interface/Services/IFundingDecisionService.cs index bcfe4c1..6ee3a21 100644 --- a/aspnetcore/src/Interface/Services/IFundingDecisionService.cs +++ b/aspnetcore/src/Interface/Services/IFundingDecisionService.cs @@ -6,5 +6,6 @@ namespace CSC.PublicApi.Interface.Services; public interface IFundingDecisionService { - Task<(IEnumerable, SearchResult)> GetFundingDecisions(GetFundingDecisionQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetFundingDecisions(GetFundingDecisionQueryParameters fundingDecisionQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetFundingDecisionsSearchAfter(GetFundingDecisionQueryParameters fundingDecisionQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IInfrastructureService.cs b/aspnetcore/src/Interface/Services/IInfrastructureService.cs index fb9e2ff..f5263be 100644 --- a/aspnetcore/src/Interface/Services/IInfrastructureService.cs +++ b/aspnetcore/src/Interface/Services/IInfrastructureService.cs @@ -6,5 +6,6 @@ namespace CSC.PublicApi.Interface.Services; public interface IInfrastructureService { - Task<(IEnumerable, SearchResult)> GetInfrastructures(GetInfrastructuresQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetInfrastructures(GetInfrastructuresQueryParameters infrastructuresQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetInfrastructuresSearchAfter(GetInfrastructuresQueryParameters infrastructuresQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IOrganizationService.cs b/aspnetcore/src/Interface/Services/IOrganizationService.cs index c9e3cc0..a10330a 100644 --- a/aspnetcore/src/Interface/Services/IOrganizationService.cs +++ b/aspnetcore/src/Interface/Services/IOrganizationService.cs @@ -6,5 +6,6 @@ namespace CSC.PublicApi.Interface.Services; public interface IOrganizationService { - Task<(IEnumerable, SearchResult)> GetOrganizations(GetOrganizationsQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetOrganizations(GetOrganizationsQueryParameters organizationsQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetOrganizationsSearchAfter(GetOrganizationsQueryParameters organizationsQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IPublicationService.cs b/aspnetcore/src/Interface/Services/IPublicationService.cs index 93d9adb..bdb0c16 100644 --- a/aspnetcore/src/Interface/Services/IPublicationService.cs +++ b/aspnetcore/src/Interface/Services/IPublicationService.cs @@ -6,7 +6,8 @@ namespace CSC.PublicApi.Interface.Services; public interface IPublicationService { - Task<(IEnumerable, SearchResult)> GetPublications(GetPublicationsQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetPublications(GetPublicationsQueryParameters publicationsQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetPublicationsSearchAfter(GetPublicationsQueryParameters publicationsQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); Task GetPublication(string publicationId); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/IResearchDataSetService.cs b/aspnetcore/src/Interface/Services/IResearchDataSetService.cs index 90ef97e..920417c 100644 --- a/aspnetcore/src/Interface/Services/IResearchDataSetService.cs +++ b/aspnetcore/src/Interface/Services/IResearchDataSetService.cs @@ -6,5 +6,6 @@ namespace CSC.PublicApi.Interface.Services; public interface IResearchDatasetService { - Task<(IEnumerable, SearchResult)> GetResearchDatasets(GetResearchDatasetsQueryParameters queryParameters); + Task<(IEnumerable, SearchResult)> GetResearchDatasets(GetResearchDatasetsQueryParameters researchDatasetsQueryParameters, PaginationQueryParameters paginationQueryParameters); + Task<(IEnumerable, SearchAfterResult)> GetResearchDatasetsSearchAfter(GetResearchDatasetsQueryParameters researchDatasetsQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters); } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/InfrastructureService.cs b/aspnetcore/src/Interface/Services/InfrastructureService.cs index 8975882..9f1e4eb 100644 --- a/aspnetcore/src/Interface/Services/InfrastructureService.cs +++ b/aspnetcore/src/Interface/Services/InfrastructureService.cs @@ -19,12 +19,22 @@ public InfrastructureService(ILogger logger, IMapper mapp _searchService = searchService; } - public async Task<(IEnumerable, SearchResult)> GetInfrastructures(GetInfrastructuresQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetInfrastructures(GetInfrastructuresQueryParameters infrastructuresQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(infrastructuresQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + + + public async Task<(IEnumerable, SearchAfterResult)> GetInfrastructuresSearchAfter(GetInfrastructuresQueryParameters infrastructuresQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(infrastructuresQueryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/OrganizationService.cs b/aspnetcore/src/Interface/Services/OrganizationService.cs index c026e52..ee81691 100644 --- a/aspnetcore/src/Interface/Services/OrganizationService.cs +++ b/aspnetcore/src/Interface/Services/OrganizationService.cs @@ -19,12 +19,22 @@ public OrganizationService(ILogger logger, IMapper mapper, _searchService = searchService; } - public async Task<(IEnumerable, SearchResult)> GetOrganizations(GetOrganizationsQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetOrganizations(GetOrganizationsQueryParameters organizationsQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(organizationsQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + + + public async Task<(IEnumerable, SearchAfterResult)> GetOrganizationsSearchAfter(GetOrganizationsQueryParameters organizationsQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(organizationsQueryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } } \ No newline at end of file diff --git a/aspnetcore/src/Interface/Services/PublicationService.cs b/aspnetcore/src/Interface/Services/PublicationService.cs index e8532d4..2033b58 100644 --- a/aspnetcore/src/Interface/Services/PublicationService.cs +++ b/aspnetcore/src/Interface/Services/PublicationService.cs @@ -17,15 +17,24 @@ public PublicationService(IMapper mapper, ISearchService, SearchResult)> GetPublications(GetPublicationsQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetPublications(GetPublicationsQueryParameters publicationsQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(publicationsQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + public async Task<(IEnumerable, SearchAfterResult)> GetPublicationsSearchAfter(GetPublicationsQueryParameters publicationsQueryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(publicationsQueryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } + public async Task GetPublication(string publicationId) { var result = await _searchService.GetSingle(publicationId); diff --git a/aspnetcore/src/Interface/Services/ResearchDatasetService.cs b/aspnetcore/src/Interface/Services/ResearchDatasetService.cs index deb7c2a..42a30ec 100644 --- a/aspnetcore/src/Interface/Services/ResearchDatasetService.cs +++ b/aspnetcore/src/Interface/Services/ResearchDatasetService.cs @@ -19,12 +19,21 @@ public ResearchDatasetService(ILogger logger, IMapper ma _searchService = searchService; } - public async Task<(IEnumerable, SearchResult)> GetResearchDatasets(GetResearchDatasetsQueryParameters queryParameters) + public async Task<(IEnumerable, SearchResult)> GetResearchDatasets(GetResearchDatasetsQueryParameters researchDatasetsQueryParameters, PaginationQueryParameters paginationQueryParameters) { - var searchParameters = _mapper.Map(queryParameters); + var searchParameters = _mapper.Map(researchDatasetsQueryParameters); - var (result, searchResult) = await _searchService.Search(searchParameters, queryParameters.PageNumber, queryParameters.PageSize); + var (result, searchResult) = await _searchService.Search(searchParameters, paginationQueryParameters.PageNumber, paginationQueryParameters.PageSize); return (_mapper.Map>(result), searchResult); } + + public async Task<(IEnumerable, SearchAfterResult)> GetResearchDatasetsSearchAfter(GetResearchDatasetsQueryParameters queryParameters, SearchAfterQueryParameters searchAfterQueryParameters) + { + var searchParameters = _mapper.Map(queryParameters); + + var (result, searchAfterResult) = await _searchService.SearchAfter(searchParameters, searchAfterQueryParameters.PageSize, searchAfterQueryParameters.NextPageToken); + + return (_mapper.Map>(result), searchAfterResult); + } } \ No newline at end of file diff --git a/aspnetcore/test/Interface.Tests/Configuration/IndexNameSettingsTest.cs b/aspnetcore/test/Interface.Tests/Configuration/IndexNameSettingsTest.cs index 9fc6710..d506a03 100644 --- a/aspnetcore/test/Interface.Tests/Configuration/IndexNameSettingsTest.cs +++ b/aspnetcore/test/Interface.Tests/Configuration/IndexNameSettingsTest.cs @@ -2,6 +2,9 @@ using CSC.PublicApi.Service.Models.FundingCall; using CSC.PublicApi.Service.Models.FundingDecision; using CSC.PublicApi.Service.Models.ResearchDataset; +using CSC.PublicApi.Service.Models.Publication; +using CSC.PublicApi.Service.Models.Infrastructure; +using CSC.PublicApi.Service.Models.Organization; using FluentAssertions; using Xunit; @@ -16,32 +19,43 @@ public IndexNameSettingsTest() _settings = new IndexNameSettings(); } + [Fact] + public void GetIndexNameForType_Publication_ShouldReturnIndexName() + { + // Arrange + _settings["CSC.PublicApi.Service.Models.Publication.Publication"] = "publication index name"; + + // Act + var actual = _settings.GetIndexNameForType(typeof(Publication)); + + // Assert + actual.Should().Be("publication index name"); + } + [Fact] public void GetIndexNameForType_FundingDecision_ShouldReturnIndexName() { // Arrange - _settings["CSC.PublicApi.Service.Models.FundingDecision.FundingDecision"] = "some index name"; + _settings["CSC.PublicApi.Service.Models.FundingDecision.FundingDecision"] = "funding decision index name"; // Act var actual = _settings.GetIndexNameForType(typeof(FundingDecision)); // Assert - actual.Should().Be("some index name"); - + actual.Should().Be("funding decision index name"); } [Fact] public void GetIndexNameForType_FundingCall_ShouldReturnIndexName() { // Arrange - _settings["CSC.PublicApi.Service.Models.FundingCall.FundingCall"] = "some index name"; + _settings["CSC.PublicApi.Service.Models.FundingCall.FundingCall"] = "funding call index name"; // Act var actual = _settings.GetIndexNameForType(typeof(FundingCall)); // Assert - actual.Should().Be("some index name"); - + actual.Should().Be("funding call index name"); } [Fact] @@ -55,6 +69,31 @@ public void GetIndexNameForType_ResearchDataset_ShouldReturnIndexName() // Assert actual.Should().Be("some index name"); + } + + [Fact] + public void GetIndexNameForType_Infrastructure_ShouldReturnIndexName() + { + // Arrange + _settings["CSC.PublicApi.Service.Models.Infrastructure.Infrastructure"] = "infrastructure index name"; + + // Act + var actual = _settings.GetIndexNameForType(typeof(Infrastructure)); + + // Assert + actual.Should().Be("infrastructure index name"); + } + [Fact] + public void GetIndexNameForType_Organization_ShouldReturnIndexName() + { + // Arrange + _settings["CSC.PublicApi.Service.Models.Organization.Organization"] = "organization index name"; + + // Act + var actual = _settings.GetIndexNameForType(typeof(Service.Models.Organization.Organization)); + + // Assert + actual.Should().Be("organization index name"); } } \ No newline at end of file diff --git a/aspnetcore/test/Interface.Tests/FundingCallControllerTest.cs b/aspnetcore/test/Interface.Tests/FundingCallControllerTest.cs index 8392df7..ee65603 100644 --- a/aspnetcore/test/Interface.Tests/FundingCallControllerTest.cs +++ b/aspnetcore/test/Interface.Tests/FundingCallControllerTest.cs @@ -42,10 +42,11 @@ public void Get_PaginationWithSpecifiedParameters_IsSuccessful() // Arrange const int pageNumber = 7; const int pageSize = 50; - var queryParameters = new GetFundingCallQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; + var queryParameters = new GetFundingCallQueryParameters {}; + var paginationQueryParameters = new PaginationQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; // Act - var result = _controller.Get(queryParameters); + var result = _controller.Get(queryParameters, paginationQueryParameters); // Assert result.Should().NotBeNull(); @@ -58,10 +59,11 @@ public void Get_PaginationWithNegativeValues_UseOneInstead() // Arrange const int pageNumber = -1; const int pageSize = -5; - var queryParameters = new GetFundingCallQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; + var queryParameters = new GetFundingCallQueryParameters {}; + var paginationQueryParameters = new PaginationQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; // Act - var result = _controller.Get(queryParameters); + var result = _controller.Get(queryParameters, paginationQueryParameters); // Assert result.Should().NotBeNull(); @@ -76,7 +78,9 @@ public void Get_PaginationWithNoSpecifiedParameters_UsesDefaultValues() const int defaultSize = 20; // Act - var result = _controller.Get(new GetFundingCallQueryParameters()); + var result = _controller.Get( + new GetFundingCallQueryParameters(), + new PaginationQueryParameters()); // Assert result.Should().NotBeNull(); @@ -90,10 +94,11 @@ public void Get_PaginationWithTooLargePageSize_SetsPageSizeToMaximum() const int maximumPageSize = 100; const int pageNumber = 7; const int pageSize = 150; - var queryParameters = new GetFundingCallQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; + var queryParameters = new GetFundingCallQueryParameters {}; + var paginationQueryParameters = new PaginationQueryParameters { PageSize = pageSize, PageNumber = pageNumber }; // Act - var result = _controller.Get(queryParameters); + var result = _controller.Get(queryParameters, paginationQueryParameters); // Assert result.Should().NotBeNull();