From 9ba739cd83ccfb1d9b73a6dde57f69dc92781c06 Mon Sep 17 00:00:00 2001 From: Kamiel Ahmadpour Date: Sat, 16 Nov 2024 18:20:35 +0000 Subject: [PATCH] native api --- .../management/v2/rest/mapper/ApiMapper.java | 3 +- .../management/v2/rest/mapper/PlanMapper.java | 4 + .../v2/rest/model/NativeApiCRDSpec.java | 7 +- .../v2/rest/model/NativePlanCRD.java | 69 +++++++ .../v2/rest/resource/api/ApisResource.java | 2 +- .../v4/nativeapi/UpdateNativeApiEntity.java | 176 ++++++++++++++++++ .../ValidateNativeApiCRDDomainService.java | 3 +- .../core/api/model/crd/NativeApiCRDSpec.java | 11 +- .../core/api/model/crd/NativePlanCRD.java | 69 +++++++ .../use_case/ImportNativeApiCRDUseCase.java | 22 +-- .../use_case/ValidateNativeApiCRDUseCase.java | 3 +- .../CreatePlanDomainService.java | 41 ++-- .../UpdatePlanDomainService.java | 13 +- .../apim/infra/adapter/ApiAdapter.java | 5 +- .../apim/infra/adapter/PlanAdapter.java | 11 ++ .../api/UpdateApiDomainServiceImpl.java | 2 +- .../api/use_case/ImportApiCRDUseCaseTest.java | 3 +- 17 files changed, 402 insertions(+), 42 deletions(-) create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativePlanCRD.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/v4/nativeapi/UpdateNativeApiEntity.java create mode 100644 gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativePlanCRD.java diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/ApiMapper.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/ApiMapper.java index 71f314a5c26..d5fa763f36b 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/ApiMapper.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/ApiMapper.java @@ -232,7 +232,8 @@ io.gravitee.rest.api.management.v2.rest.model.ApiV1 mapToV1( @Mapping(target = "plans", qualifiedByName = "mapPlanCRD") ApiCRDSpec map(io.gravitee.rest.api.management.v2.rest.model.ApiCRDSpec crd); - @Mapping(target = "plans", qualifiedByName = "mapPlanCRD") + @Mapping(target = "listeners", qualifiedByName = "toNativeListeners") + @Mapping(target = "metadata", ignore = true) NativeApiCRDSpec map(io.gravitee.rest.api.management.v2.rest.model.NativeApiCRDSpec crd); @Mapping(target = "source.configuration", qualifiedByName = "serializeConfiguration") diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/PlanMapper.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/PlanMapper.java index b20f0abf89e..a9db8009882 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/PlanMapper.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/mapper/PlanMapper.java @@ -25,6 +25,7 @@ import io.gravitee.rest.api.management.v2.rest.model.CreatePlanV2; import io.gravitee.rest.api.management.v2.rest.model.CreatePlanV4; import io.gravitee.rest.api.management.v2.rest.model.FlowV4; +import io.gravitee.rest.api.management.v2.rest.model.NativePlanCRD; import io.gravitee.rest.api.management.v2.rest.model.Plan; import io.gravitee.rest.api.management.v2.rest.model.PlanCRD; import io.gravitee.rest.api.management.v2.rest.model.PlanFederated; @@ -154,6 +155,9 @@ default io.gravitee.apim.core.plan.model.Plan map(CreatePlanV4 source, Api api) @Mapping(target = "security", qualifiedByName = "mapToPlanSecurityV4") io.gravitee.apim.core.api.model.crd.PlanCRD fromPlanCRD(PlanCRD plan); + @Mapping(target = "security", qualifiedByName = "mapToPlanSecurityV4") + io.gravitee.apim.core.api.model.crd.NativePlanCRD fromPlanCRD(NativePlanCRD plan); + @Mapping(target = "security.configuration", qualifiedByName = "serializeConfiguration") UpdatePlanEntity map(UpdatePlanV4 plan); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativeApiCRDSpec.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativeApiCRDSpec.java index f0c06ef0b23..5b85fccba0f 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativeApiCRDSpec.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativeApiCRDSpec.java @@ -15,6 +15,11 @@ */ package io.gravitee.rest.api.management.v2.rest.model; +import io.gravitee.definition.model.DefinitionContext; +import io.gravitee.definition.model.DefinitionVersion; +import io.gravitee.definition.model.ResponseTemplate; +import io.gravitee.definition.model.v4.flow.execution.FlowExecution; +import io.gravitee.definition.model.v4.service.ApiServices; import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -66,7 +71,7 @@ public class NativeApiCRDSpec { private List<@Valid Resource> resources = new ArrayList<>(); - private Map plans = new HashMap<>(); + private Map plans = new HashMap<>(); private FlowExecution flowExecution; diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativePlanCRD.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativePlanCRD.java new file mode 100644 index 00000000000..04d6a60abfe --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/model/NativePlanCRD.java @@ -0,0 +1,69 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.rest.api.management.v2.rest.model; + +import io.gravitee.definition.model.v4.nativeapi.NativeFlow; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class NativePlanCRD { + + @NotNull + @NotEmpty + private String id; + + private String crossId; + + private String name; + + private String description; + + private PlanSecurity security; + + private List characteristics; + + private List excludedGroups; + + private String generalConditions; + + private int order; + + private String selectionRule; + + @NotNull + private PlanStatus status; + + private List tags; + + @NotNull + private PlanType type; + + private PlanValidation validation; + + private List flows; + + @NotNull + private PlanMode mode; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApisResource.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApisResource.java index ae2cce94640..6405ea1f6a1 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApisResource.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApisResource.java @@ -242,7 +242,7 @@ public Response createApiWithCRD(@Valid ApiCRDSpec crd, @QueryParam("dryRun") bo } @PUT - @Path("/_import/native/crd") + @Path("/_import/native-crd") @Produces(MediaType.APPLICATION_JSON) @Permissions({ @Permission(value = RolePermission.ENVIRONMENT_API, acls = RolePermissionAction.CREATE) }) public Response createNativeApiWithCRD(@Valid NativeApiCRDSpec crd, @QueryParam("dryRun") boolean dryRun) { diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/v4/nativeapi/UpdateNativeApiEntity.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/v4/nativeapi/UpdateNativeApiEntity.java new file mode 100644 index 00000000000..53593069c6d --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-model/src/main/java/io/gravitee/rest/api/model/v4/nativeapi/UpdateNativeApiEntity.java @@ -0,0 +1,176 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.rest.api.model.v4.nativeapi; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.gravitee.common.component.Lifecycle; +import io.gravitee.definition.model.DefinitionVersion; +import io.gravitee.definition.model.v4.ApiType; +import io.gravitee.definition.model.v4.nativeapi.NativeApiServices; +import io.gravitee.definition.model.v4.nativeapi.NativeEndpointGroup; +import io.gravitee.definition.model.v4.nativeapi.NativeFlow; +import io.gravitee.definition.model.v4.nativeapi.NativeListener; +import io.gravitee.definition.model.v4.property.Property; +import io.gravitee.definition.model.v4.resource.Resource; +import io.gravitee.rest.api.model.DeploymentRequired; +import io.gravitee.rest.api.model.PrimaryOwnerEntity; +import io.gravitee.rest.api.model.Visibility; +import io.gravitee.rest.api.model.WorkflowState; +import io.gravitee.rest.api.model.api.ApiLifecycleState; +import io.gravitee.rest.api.model.context.OriginContext; +import io.gravitee.rest.api.model.v4.api.GenericApiEntity; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.With; + +/** + * @author Guillaume LAMIRAND (guillaume.lamirand at graviteesource.com) + * @author GraviteeSource Team + */ +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ToString +@EqualsAndHashCode +@Schema(name = "UpdateNativeApiEntityV4") +@Builder(toBuilder = true) +@With +public class UpdateNativeApiEntity { + + @Schema(description = "API's uuid.", example = "00f8c9e7-78fc-4907-b8c9-e778fc790750") + private String id; + + @Schema(description = "API's crossId. Identifies API across environments.", example = "df83b2a4-cc3e-3f80-9f0d-c138c106c076") + private String crossId; + + @Schema(description = "API's name. Duplicate names can exists.", example = "My Api") + private String name; + + @Schema(description = "Api's version. It's a simple string only used in the portal.", example = "v1.0") + private String apiVersion; + + @Schema(description = "API's gravitee definition version") + private DefinitionVersion definitionVersion; + + @Schema( + description = "API's description. A short description of your API.", + example = "I can use a hundred characters to describe this API." + ) + private String description; + + @Schema(description = "The list of sharding tags associated with this API.", example = "public, private") + @DeploymentRequired + @Builder.Default + private Set tags = new HashSet<>(); + + @Schema(description = "A list of listeners used to describe our you api could be reached.") + @DeploymentRequired + private List listeners; + + @Schema(description = "A list of endpoint describing the endpoints to contact.") + @DeploymentRequired + private List endpointGroups; + + @Schema(description = "A dictionary (could be dynamic) of properties available in the API context.") + @DeploymentRequired + @Builder.Default + private List properties = new ArrayList<>(); + + @Schema(description = "The list of API resources used by policies like cache resources or oauth2") + @DeploymentRequired + @Builder.Default + private List resources = new ArrayList<>(); + + @Schema(description = "A list of plans to apply on the API") + @DeploymentRequired + @Builder.Default + private Set plans = new HashSet<>(); + + @Schema(description = "A list of flows containing the policies configuration.") + @DeploymentRequired + private List flows; + + @DeploymentRequired + @Schema(description = "The configuration of API services like the dynamic properties.") + private NativeApiServices services; + + @Schema(description = "API's groups. Used to add team in your API.", example = "['MY_GROUP1', 'MY_GROUP2']") + private Set groups; + + @Schema(description = "The visibility of the API regarding the portal.", example = "PUBLIC") + private Visibility visibility; + + @Schema(description = "The user with role PRIMARY_OWNER on this API.") + private PrimaryOwnerEntity primaryOwner; + + @Schema(description = "the API logo encoded in base64") + private String picture; + + @Schema( + description = "the API logo URL.", + example = "https://gravitee.mycompany.com/management/apis/6c530064-0b2c-4004-9300-640b2ce0047b/picture" + ) + private String pictureUrl; + + @Schema(description = "the list of categories associated with this API", example = "Product, Customer, Misc") + private Set categories; + + @Schema(description = "the free list of labels associated with this API", example = "json, read_only, awesome") + private List labels; + + /** Context explaining where the API comes from. */ + @Builder.Default + private OriginContext originContext = new OriginContext.Management(); + + @JsonIgnore + @Builder.Default + private Map metadata = new HashMap<>(); + + private ApiLifecycleState lifecycleState; + + private WorkflowState workflowState; + + private boolean disableMembershipNotifications; + + @Schema(description = "the API background encoded in base64") + private String background; + + @Schema( + description = "the API background url.", + example = "https://gravitee.mycompany.com/management/apis/6c530064-0b2c-4004-9300-640b2ce0047b/background" + ) + private String backgroundUrl; + + @JsonIgnore + private String referenceType; + + @JsonIgnore + private String referenceId; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateNativeApiCRDDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateNativeApiCRDDomainService.java index fbd5c13aefc..9c1f23beb39 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateNativeApiCRDDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateNativeApiCRDDomainService.java @@ -26,9 +26,8 @@ import io.gravitee.apim.core.member.model.MembershipReferenceType; import io.gravitee.apim.core.resource.domain_service.ValidateResourceDomainService; import io.gravitee.apim.core.validation.Validator; -import lombok.RequiredArgsConstructor; - import java.util.ArrayList; +import lombok.RequiredArgsConstructor; /** * @author Antoine CORDIER (antoine.cordier at graviteesource.com) diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativeApiCRDSpec.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativeApiCRDSpec.java index b0eed3e09b0..b996b5fd98c 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativeApiCRDSpec.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativeApiCRDSpec.java @@ -37,14 +37,14 @@ import io.gravitee.definition.model.v4.property.Property; import io.gravitee.definition.model.v4.resource.Resource; import io.gravitee.rest.api.model.context.OriginContext; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * @author Antoine CORDIER (antoine.cordier at graviteesource.com) @@ -81,8 +81,8 @@ public class NativeApiCRDSpec { private Set labels; private List resources; + private Map plans; - private Map plans; private List properties; @@ -158,5 +158,4 @@ public Api.ApiBuilder toApiBuilder() { .tags(tags) .type(ApiType.valueOf(type)); } - } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativePlanCRD.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativePlanCRD.java new file mode 100644 index 00000000000..cd3b8dc1073 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/crd/NativePlanCRD.java @@ -0,0 +1,69 @@ +/* + * Copyright © 2015 The Gravitee team (http://gravitee.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.gravitee.apim.core.api.model.crd; + +import io.gravitee.apim.core.plan.model.Plan; +import io.gravitee.definition.model.v4.flow.Flow; +import io.gravitee.definition.model.v4.nativeapi.NativeFlow; +import io.gravitee.definition.model.v4.plan.PlanMode; +import io.gravitee.definition.model.v4.plan.PlanSecurity; +import io.gravitee.definition.model.v4.plan.PlanStatus; +import java.util.List; +import java.util.Set; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@Builder(toBuilder = true) +public class NativePlanCRD { + + private String id; + + private String crossId; + + private String name; + + private String description; + + private PlanSecurity security; + + private List characteristics; + + private List excludedGroups; + + private String generalConditions; + + private int order; + + private String selectionRule; + + private PlanStatus status; + + private Set tags; + + private Plan.PlanType type; + + private Plan.PlanValidationType validation; + + @Builder.Default + private List flows = List.of(); + + private PlanMode mode; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ImportNativeApiCRDUseCase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ImportNativeApiCRDUseCase.java index f7274ead144..cc04c3d9941 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ImportNativeApiCRDUseCase.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ImportNativeApiCRDUseCase.java @@ -25,15 +25,13 @@ import io.gravitee.apim.core.api.domain_service.ApiStateDomainService; import io.gravitee.apim.core.api.domain_service.CreateApiDomainService; import io.gravitee.apim.core.api.domain_service.UpdateApiDomainService; -import io.gravitee.apim.core.api.domain_service.ValidateApiCRDDomainService; import io.gravitee.apim.core.api.domain_service.ValidateApiDomainService; import io.gravitee.apim.core.api.domain_service.ValidateNativeApiCRDDomainService; import io.gravitee.apim.core.api.model.Api; -import io.gravitee.apim.core.api.model.crd.ApiCRDSpec; import io.gravitee.apim.core.api.model.crd.ApiCRDStatus; import io.gravitee.apim.core.api.model.crd.NativeApiCRDSpec; +import io.gravitee.apim.core.api.model.crd.NativePlanCRD; import io.gravitee.apim.core.api.model.crd.PageCRD; -import io.gravitee.apim.core.api.model.crd.PlanCRD; import io.gravitee.apim.core.api.model.factory.ApiModelFactory; import io.gravitee.apim.core.api.query_service.ApiQueryService; import io.gravitee.apim.core.audit.model.AuditInfo; @@ -58,6 +56,7 @@ import io.gravitee.apim.core.subscription.query_service.SubscriptionQueryService; import io.gravitee.apim.core.validation.Validator; import io.gravitee.common.utils.TimeProvider; +import io.gravitee.definition.model.v4.nativeapi.NativePlan; import io.gravitee.definition.model.v4.plan.PlanStatus; import io.gravitee.rest.api.model.context.OriginContext; import io.gravitee.rest.api.service.exceptions.TechnicalManagementException; @@ -349,14 +348,14 @@ private void deletePlans(Api api, List existingPlans, Map reorderPlanDomainService.refreshOrderAfterDelete(api.getId()); } - private Plan initPlanFromCRD(PlanCRD planCRD) { + private Plan initPlanFromCRD(NativePlanCRD planCRD) { return Plan .builder() .id(planCRD.getId()) .name(planCRD.getName()) .description(planCRD.getDescription()) - .planDefinitionHttpV4( - io.gravitee.definition.model.v4.plan.Plan + .planDefinitionNativeV4( + NativePlan .builder() .security(planCRD.getSecurity()) .selectionRule(planCRD.getSelectionRule()) @@ -409,11 +408,12 @@ private void createOrUpdatePages(Map pageCRDs, String apiId, Au pageCrudService .findById(page.getId()) .ifPresentOrElse( - oldPage -> updateApiDocumentationDomainService.updatePage( - page.toBuilder().createdAt(oldPage.getCreatedAt()).updatedAt(now).build(), - oldPage, - auditInfo - ), + oldPage -> + updateApiDocumentationDomainService.updatePage( + page.toBuilder().createdAt(oldPage.getCreatedAt()).updatedAt(now).build(), + oldPage, + auditInfo + ), () -> createApiDocumentationDomainService.createPage(page.toBuilder().createdAt(now).updatedAt(now).build(), auditInfo) ); }); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ValidateNativeApiCRDUseCase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ValidateNativeApiCRDUseCase.java index 2f1edfb8cfa..19b30a8e2fa 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ValidateNativeApiCRDUseCase.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/ValidateNativeApiCRDUseCase.java @@ -19,10 +19,9 @@ import io.gravitee.apim.core.api.domain_service.ValidateApiCRDDomainService; import io.gravitee.apim.core.api.domain_service.ValidateNativeApiCRDDomainService; import io.gravitee.apim.core.api.model.crd.ApiCRDStatus; -import lombok.RequiredArgsConstructor; - import java.util.Map; import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; /** * @author Antoine CORDIER (antoine.cordier at graviteesource.com) diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/CreatePlanDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/CreatePlanDomainService.java index b5984595f37..d0e4f81d5f7 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/CreatePlanDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/CreatePlanDomainService.java @@ -29,10 +29,13 @@ import io.gravitee.apim.core.plan.model.Plan; import io.gravitee.apim.core.plan.model.PlanWithFlows; import io.gravitee.common.utils.TimeProvider; +import io.gravitee.definition.model.v4.flow.AbstractFlow; import io.gravitee.definition.model.v4.flow.Flow; import io.gravitee.definition.model.v4.listener.Listener; +import io.gravitee.definition.model.v4.nativeapi.NativeFlow; import io.gravitee.rest.api.service.common.UuidString; import java.sql.Date; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -61,7 +64,7 @@ public CreatePlanDomainService( this.auditService = auditDomainService; } - public PlanWithFlows create(Plan plan, List flows, Api api, AuditInfo auditInfo) { + public PlanWithFlows create(Plan plan, List flows, Api api, AuditInfo auditInfo) { return switch (api.getDefinitionVersion()) { case V4 -> createV4ApiPlan(plan, flows, api, auditInfo); case FEDERATED -> createFederatedApiPlan(plan, auditInfo); @@ -69,7 +72,7 @@ public PlanWithFlows create(Plan plan, List flows, Api api, AuditInfo audi }; } - private PlanWithFlows createV4ApiPlan(Plan plan, List flows, Api api, AuditInfo auditInfo) { + private PlanWithFlows createV4ApiPlan(Plan plan, List flows, Api api, AuditInfo auditInfo) { if (api.isDeprecated()) { throw new ApiDeprecatedException(plan.getApiId()); } @@ -85,12 +88,18 @@ private PlanWithFlows createV4ApiPlan(Plan plan, List flows, Api api, Audi planValidatorDomainService.validatePlanTagsAgainstApiTags(plan.getPlanDefinitionHttpV4().getTags(), api.getTags()); planValidatorDomainService.validateGeneralConditionsPageStatus(plan); - var sanitizedFlows = flowValidationDomainService.validateAndSanitizeHttpV4(api.getType(), flows); - flowValidationDomainService.validatePathParameters( - api.getType(), - api.getApiDefinitionHttpV4().getFlows() != null ? api.getApiDefinitionHttpV4().getFlows().stream() : Stream.empty(), - sanitizedFlows.stream() - ); + List sanitizedFlows = new ArrayList<>(); + List sanitizedNativeFlows = new ArrayList<>(); + if (!flows.isEmpty() && flows.get(0) instanceof Flow) { + sanitizedFlows = flowValidationDomainService.validateAndSanitizeHttpV4(api.getType(), (List) flows); + flowValidationDomainService.validatePathParameters( + api.getType(), + api.getApiDefinitionHttpV4().getFlows() != null ? api.getApiDefinitionHttpV4().getFlows().stream() : Stream.empty(), + sanitizedFlows.stream() + ); + } else if (!flows.isEmpty() && flows.get(0) instanceof NativeFlow) { + sanitizedNativeFlows = flowValidationDomainService.validateAndSanitizeNativeV4((List) flows); + } var createdPlan = planCrudService.create( plan @@ -105,11 +114,19 @@ private PlanWithFlows createV4ApiPlan(Plan plan, List flows, Api api, Audi .build() ); - var createdFlows = flowCrudService.savePlanFlows(createdPlan.getId(), sanitizedFlows); + if (!sanitizedFlows.isEmpty()) { + var createdFlows = flowCrudService.savePlanFlows(createdPlan.getId(), sanitizedFlows); + createAuditLog(createdPlan, auditInfo); - createAuditLog(createdPlan, auditInfo); + return toPlanWithFlows(createdPlan, createdFlows); + } else if (!sanitizedNativeFlows.isEmpty()) { + var createdNativeFlows = flowCrudService.saveNativeApiFlows(createdPlan.getId(), sanitizedNativeFlows); + createAuditLog(createdPlan, auditInfo); + + return toPlanWithFlows(createdPlan, createdNativeFlows); + } - return toPlanWithFlows(createdPlan, createdFlows); + return null; } private PlanWithFlows createFederatedApiPlan(Plan plan, AuditInfo auditInfo) { @@ -134,7 +151,7 @@ private void createAuditLog(Plan createdPlan, AuditInfo auditInfo) { ); } - private PlanWithFlows toPlanWithFlows(Plan plan, List flows) { + private PlanWithFlows toPlanWithFlows(Plan plan, List flows) { return PlanWithFlows .builder() .flows(flows) diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/UpdatePlanDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/UpdatePlanDomainService.java index 4be673951f3..913346e4762 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/UpdatePlanDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/plan/domain_service/UpdatePlanDomainService.java @@ -30,6 +30,7 @@ import io.gravitee.apim.core.plan.crud_service.PlanCrudService; import io.gravitee.apim.core.plan.model.Plan; import io.gravitee.apim.core.plan.query_service.PlanQueryService; +import io.gravitee.definition.model.v4.flow.AbstractFlow; import io.gravitee.definition.model.v4.flow.Flow; import io.gravitee.definition.model.v4.plan.PlanStatus; import java.util.Date; @@ -68,7 +69,13 @@ public UpdatePlanDomainService( this.reorderPlanDomainService = reorderPlanDomainService; } - public Plan update(Plan planToUpdate, List flows, Map existingPlanStatuses, Api api, AuditInfo auditInfo) { + public Plan update( + Plan planToUpdate, + List flows, + Map existingPlanStatuses, + Api api, + AuditInfo auditInfo + ) { return switch (planToUpdate.getDefinitionVersion()) { case V4 -> { if (existingPlanStatuses == null) { @@ -92,7 +99,7 @@ public Plan update(Plan planToUpdate, List flows, Map */ private Plan updateV4ApiPlan( Plan planToUpdate, - List flows, + List flows, Map existingPlanStatuses, Api api, AuditInfo auditInfo @@ -109,7 +116,7 @@ private Plan updateV4ApiPlan( planValidatorDomainService.validatePlanTagsAgainstApiTags(planToUpdate.getPlanDefinitionV4().getTags(), api.getTags()); planValidatorDomainService.validateGeneralConditionsPageStatus(planToUpdate); - var sanitizedFlows = flowValidationDomainService.validateAndSanitizeHttpV4(api.getType(), flows); + var sanitizedFlows = flowValidationDomainService.validateAndSanitizeHttpV4(api.getType(), (List) flows); flowValidationDomainService.validatePathParameters( api.getType(), api.getApiDefinitionHttpV4().getFlows().stream(), diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/ApiAdapter.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/ApiAdapter.java index 6fc1d5253ed..2bccc6e1607 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/ApiAdapter.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/ApiAdapter.java @@ -28,6 +28,7 @@ import io.gravitee.rest.api.model.v4.api.GenericApiEntity; import io.gravitee.rest.api.model.v4.api.NewApiEntity; import io.gravitee.rest.api.model.v4.api.UpdateApiEntity; +import io.gravitee.rest.api.model.v4.nativeapi.UpdateNativeApiEntity; import java.io.IOException; import java.util.stream.Stream; import org.mapstruct.DecoratedWith; @@ -78,7 +79,9 @@ public interface ApiAdapter { @ValueMapping(source = MappingConstants.ANY_REMAINING, target = MappingConstants.NULL) @Mapping(source = "version", target = "apiVersion") @Mapping(target = "disableMembershipNotifications", expression = "java(!spec.isNotifyMembers())") - UpdateApiEntity toUpdateApiEntity(NativeApiCRDSpec spec); + @Mapping(target = "plans", qualifiedByName = "toNativePlanEntityV4") + @Mapping(target = "metadata", ignore = true) + UpdateNativeApiEntity toUpdateApiEntity(NativeApiCRDSpec spec); @ValueMapping(source = MappingConstants.ANY_REMAINING, target = MappingConstants.NULL) @Mapping(target = "id", source = "api.id") diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/PlanAdapter.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/PlanAdapter.java index 06490a4f9eb..1d6ee2c38eb 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/PlanAdapter.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/adapter/PlanAdapter.java @@ -16,15 +16,18 @@ package io.gravitee.apim.infra.adapter; import com.fasterxml.jackson.core.type.TypeReference; +import io.gravitee.apim.core.api.model.crd.NativePlanCRD; import io.gravitee.apim.core.api.model.crd.PlanCRD; import io.gravitee.apim.core.plan.model.Plan; import io.gravitee.definition.model.DefinitionVersion; import io.gravitee.definition.model.Rule; import io.gravitee.definition.model.federation.FederatedPlan; import io.gravitee.definition.model.v4.ApiType; +import io.gravitee.definition.model.v4.nativeapi.NativePlan; import io.gravitee.definition.model.v4.plan.PlanMode; import io.gravitee.definition.model.v4.plan.PlanSecurity; import io.gravitee.definition.model.v4.plan.PlanStatus; +import io.gravitee.rest.api.model.v4.nativeapi.NativePlanEntity; import io.gravitee.rest.api.model.v4.plan.NewPlanEntity; import io.gravitee.rest.api.model.v4.plan.PlanEntity; import io.gravitee.rest.api.model.v4.plan.PlanSecurityType; @@ -90,6 +93,9 @@ public interface PlanAdapter { PlanEntity toEntityV4(PlanCRD source); io.gravitee.definition.model.v4.plan.Plan toApiDefinition(PlanCRD source); + NativePlanEntity toNativePlanEntityV4(NativePlanCRD source); + NativePlan toNativePlan(NativePlanCRD source); + @Mapping(target = "security", expression = "java(computeBasePlanEntitySecurityV4(source))") io.gravitee.definition.model.v4.plan.Plan toPlanDefinitionHttpV4(io.gravitee.repository.management.model.Plan source); @@ -153,6 +159,11 @@ default Set toPlanEntityV4(Map source) { return source.values().stream().map(PlanAdapter.INSTANCE::toEntityV4).collect(Collectors.toSet()); } + @Named("toNativePlanEntityV4") + default Set toNativePlanEntityV4(Map source) { + return source.values().stream().map(PlanAdapter.INSTANCE::toNativePlanEntityV4).collect(Collectors.toSet()); + } + @Named("computeBasePlanEntityMode") default PlanMode computeBasePlanEntityMode(io.gravitee.repository.management.model.Plan plan) { return plan.getMode() != null ? PlanMode.valueOf(plan.getMode().name()) : PlanMode.STANDARD; diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/UpdateApiDomainServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/UpdateApiDomainServiceImpl.java index 0ed9e2dff3b..003d52b614c 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/UpdateApiDomainServiceImpl.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/UpdateApiDomainServiceImpl.java @@ -52,7 +52,7 @@ public Api update(String apiId, ApiCRDSpec crd, AuditInfo auditInfo) { @Override public Api update(String apiId, NativeApiCRDSpec crd, AuditInfo auditInfo) { var executionContext = new ExecutionContext(auditInfo.organizationId(), auditInfo.environmentId()); - var apiEntity = delegate.update(executionContext, apiId, ApiAdapter.INSTANCE.toUpdateApiEntity(crd), auditInfo.actor().userId()); + var apiEntity = delegate.update(executionContext, apiId, null, auditInfo.actor().userId()); return apiCrudService.get(apiEntity.getId()); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/ImportApiCRDUseCaseTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/ImportApiCRDUseCaseTest.java index b4ba13cf4a5..eae6876869f 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/ImportApiCRDUseCaseTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/ImportApiCRDUseCaseTest.java @@ -723,7 +723,8 @@ class Update { @BeforeEach void setUp() { // TODO fake update API for now until we get rid of Legacy - when(updateApiDomainService.update(any(), any(), any())).thenAnswer(invocation -> API_PROXY_V4); + when(updateApiDomainService.update(anyString(), any(ApiCRDSpec.class), any(AuditInfo.class))) + .thenAnswer(invocation -> API_PROXY_V4); } @Test