diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiIndexerDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiIndexerDomainService.java index ce6cfbdba3c..09dd90833f7 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiIndexerDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiIndexerDomainService.java @@ -17,8 +17,8 @@ import io.gravitee.apim.core.DomainService; import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.ApiMetadataDecodeContext; -import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.PrimaryOwnerMetadataDecodeContext; import io.gravitee.apim.core.api.model.Api; +import io.gravitee.apim.core.documentation.model.PrimaryOwnerApiTemplateData; import io.gravitee.apim.core.membership.model.PrimaryOwnerEntity; import io.gravitee.apim.core.search.Indexer; import io.gravitee.apim.core.search.model.IndexableApi; @@ -45,7 +45,7 @@ public void index(Indexer.IndexationContext context, Api apiToIndex, PrimaryOwne .createdAt(Date.from(apiToIndex.getCreatedAt().toInstant())) .updatedAt(Date.from(apiToIndex.getUpdatedAt().toInstant())) .primaryOwner( - new PrimaryOwnerMetadataDecodeContext( + new PrimaryOwnerApiTemplateData( primaryOwner.id(), primaryOwner.displayName(), primaryOwner.email(), diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainService.java index e6336e677b2..fdd3f73258b 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainService.java @@ -16,18 +16,18 @@ package io.gravitee.apim.core.api.domain_service; import io.gravitee.apim.core.DomainService; +import io.gravitee.apim.core.api.model.Api; import io.gravitee.apim.core.api.query_service.ApiMetadataQueryService; +import io.gravitee.apim.core.documentation.model.ApiFreemarkerTemplate; import io.gravitee.apim.core.exception.TechnicalDomainException; +import io.gravitee.apim.core.membership.model.PrimaryOwnerEntity; import io.gravitee.apim.core.template.TemplateProcessor; import io.gravitee.apim.core.template.TemplateProcessorException; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.Map; import java.util.stream.Collectors; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; +import lombok.experimental.SuperBuilder; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -54,6 +54,15 @@ public Map decodeMetadata(String apiId, ApiMetadataDecodeContext return decode(metadata, context); } + public String decodeMetadataValue(String value, ApiMetadataDecodeContext context) { + try { + return templateProcessor.processInlineTemplate(value, Collections.singletonMap("api", context)); + } catch (TemplateProcessorException e) { + log.warn("Error while validating template '{}' from reader:\n{}", e.getTemplate(), e.getMessage()); + return value; + } + } + private Map decode(Map metadata, ApiMetadataDecodeContext context) { if (metadata.isEmpty()) { return metadata; @@ -74,26 +83,11 @@ private Map decode(Map metadata, ApiMetadataDeco } } - @Builder - @AllArgsConstructor - @Data - public static class ApiMetadataDecodeContext { + @SuperBuilder + public static class ApiMetadataDecodeContext extends ApiFreemarkerTemplate { - private String name; - private String description; - private Date createdAt; - private Date updatedAt; - private PrimaryOwnerMetadataDecodeContext primaryOwner; - } - - @Builder - @AllArgsConstructor - @Data - public static class PrimaryOwnerMetadataDecodeContext { - - private String id; - private String displayName; - private String email; - private String type; + public ApiMetadataDecodeContext(Api api, Map metadata, PrimaryOwnerEntity primaryOwner) { + super(api, metadata, primaryOwner); + } } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDomainService.java index 18820236759..44f1a7d6e56 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDomainService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDomainService.java @@ -17,6 +17,7 @@ import io.gravitee.apim.core.DomainService; import io.gravitee.apim.core.api.model.ApiMetadata; +import io.gravitee.apim.core.api.model.NewApiMetadata; import io.gravitee.apim.core.audit.domain_service.AuditDomainService; import io.gravitee.apim.core.audit.model.ApiAuditLogEntity; import io.gravitee.apim.core.audit.model.AuditInfo; @@ -25,6 +26,7 @@ import io.gravitee.apim.core.exception.TechnicalDomainException; import io.gravitee.apim.core.metadata.crud_service.MetadataCrudService; import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.metadata.model.MetadataId; import io.gravitee.common.utils.IdGenerator; import io.gravitee.common.utils.TimeProvider; import java.util.List; @@ -77,6 +79,46 @@ public void saveApiMetadata(String apiId, List metadata, AuditInfo throw new TechnicalDomainException("Not yet implemented"); } + public ApiMetadata create(NewApiMetadata newApiMetadata, AuditInfo auditInfo) { + var now = TimeProvider.now(); + var createdMetadata = metadataCrudService.create( + Metadata + .builder() + .key(newApiMetadata.getKey()) + .format(newApiMetadata.getFormat()) + .name(newApiMetadata.getName()) + .value(newApiMetadata.getValue()) + .referenceType(Metadata.ReferenceType.API) + .referenceId(newApiMetadata.getApiId()) + .createdAt(now) + .updatedAt(now) + .build() + ); + createAuditLog(createdMetadata, auditInfo); + + var defaultValue = + this.metadataCrudService.findById( + MetadataId + .builder() + .key(createdMetadata.getKey()) + .referenceId("_") + .referenceType(Metadata.ReferenceType.DEFAULT) + .build() + ) + .map(Metadata::getValue) + .orElse(null); + + return ApiMetadata + .builder() + .key(createdMetadata.getKey()) + .format(createdMetadata.getFormat()) + .name(createdMetadata.getName()) + .value(createdMetadata.getValue()) + .defaultValue(defaultValue) + .apiId(createdMetadata.getReferenceId()) + .build(); + } + private void createAuditLog(Metadata created, AuditInfo auditInfo) { auditService.createApiAuditLog( ApiAuditLogEntity diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainService.java new file mode 100644 index 00000000000..823599c36a1 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainService.java @@ -0,0 +1,99 @@ +/* + * 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.domain_service; + +import io.gravitee.apim.core.DomainService; +import io.gravitee.apim.core.api.exception.DuplicateApiMetadataKeyException; +import io.gravitee.apim.core.api.exception.DuplicateApiMetadataNameException; +import io.gravitee.apim.core.api.exception.InvalidApiMetadataValueException; +import io.gravitee.apim.core.api.model.Api; +import io.gravitee.apim.core.api.query_service.ApiMetadataQueryService; +import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; +import io.gravitee.apim.core.metadata.crud_service.MetadataCrudService; +import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.metadata.model.MetadataId; +import jakarta.mail.internet.InternetAddress; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Map; +import java.util.Objects; +import lombok.AllArgsConstructor; + +@AllArgsConstructor +@DomainService +public class ValidateApiMetadataDomainService { + + private final ApiMetadataQueryService metadataQueryService; + private final MetadataCrudService metadataCrudService; + private final ApiPrimaryOwnerDomainService apiPrimaryOwnerDomainService; + private final ApiMetadataDecoderDomainService apiMetadataDecoderDomainService; + + private final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + public void validateUniqueKey(String apiId, String key) { + this.metadataCrudService.findById( + MetadataId.builder().key(key).referenceId(apiId).referenceType(Metadata.ReferenceType.API).build() + ) + .ifPresent(m -> { + throw new DuplicateApiMetadataKeyException(apiId, key); + }); + } + + public void validateUniqueName(String apiId, String name) { + this.metadataQueryService.findApiMetadata(apiId) + .values() + .forEach(val -> { + if (val.getName().equalsIgnoreCase(name)) { + throw new DuplicateApiMetadataNameException(apiId, name); + } + }); + } + + public void validateValueByFormat(Api api, String organizationId, String value, Metadata.MetadataFormat format) { + var valueToCheck = Objects.nonNull(value) && value.startsWith("${") ? this.getDecodedValue(api, organizationId, value) : value; + + try { + switch (format) { + case URL: + new URL(valueToCheck); + break; + case MAIL: + final InternetAddress email = new InternetAddress(valueToCheck); + email.validate(); + break; + case DATE: + SIMPLE_DATE_FORMAT.setLenient(false); + SIMPLE_DATE_FORMAT.parse(valueToCheck); + break; + case NUMERIC: + Double.valueOf(valueToCheck); + break; + } + } catch (Exception e) { + throw new InvalidApiMetadataValueException(value, format.name()); + } + } + + private String getDecodedValue(Api api, String organizationId, String value) { + var apiTemplate = new ApiMetadataDecoderDomainService.ApiMetadataDecodeContext( + api, + Map.of(), // Metadata cannot reference another metadata entry + apiPrimaryOwnerDomainService.getApiPrimaryOwner(organizationId, api.getId()) + ); + + return this.apiMetadataDecoderDomainService.decodeMetadataValue(value, apiTemplate); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataKeyException.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataKeyException.java new file mode 100644 index 00000000000..0714a89b2f0 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataKeyException.java @@ -0,0 +1,25 @@ +/* + * 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.exception; + +import io.gravitee.apim.core.exception.ValidationDomainException; + +public class DuplicateApiMetadataKeyException extends ValidationDomainException { + + public DuplicateApiMetadataKeyException(String apiId, String key) { + super("Key [" + key + "] already exists for API [" + apiId + "]"); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataNameException.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataNameException.java new file mode 100644 index 00000000000..c471b1ff046 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/DuplicateApiMetadataNameException.java @@ -0,0 +1,25 @@ +/* + * 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.exception; + +import io.gravitee.apim.core.exception.ValidationDomainException; + +public class DuplicateApiMetadataNameException extends ValidationDomainException { + + public DuplicateApiMetadataNameException(String apiId, String name) { + super("Name [" + name + "] already exists for API [" + apiId + "]"); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/InvalidApiMetadataValueException.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/InvalidApiMetadataValueException.java new file mode 100644 index 00000000000..8c9c5dceb33 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/exception/InvalidApiMetadataValueException.java @@ -0,0 +1,25 @@ +/* + * 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.exception; + +import io.gravitee.apim.core.exception.ValidationDomainException; + +public class InvalidApiMetadataValueException extends ValidationDomainException { + + public InvalidApiMetadataValueException(String value, String format) { + super("Invalid value [" + value + "] for format [" + format + "]"); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/ApiMetadata.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/ApiMetadata.java index 118c33f0ffa..f032f6a4723 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/ApiMetadata.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/ApiMetadata.java @@ -16,7 +16,7 @@ package io.gravitee.apim.core.api.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import io.gravitee.rest.api.model.MetadataFormat; +import io.gravitee.apim.core.metadata.model.Metadata; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -32,7 +32,7 @@ public class ApiMetadata { String apiId; String key; String name; - MetadataFormat format; + Metadata.MetadataFormat format; @With String value; diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/NewApiMetadata.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/NewApiMetadata.java new file mode 100644 index 00000000000..daee0d54d58 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/model/NewApiMetadata.java @@ -0,0 +1,35 @@ +/* + * 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; + +import io.gravitee.apim.core.metadata.model.Metadata; +import lombok.*; + +@Data +@Builder(toBuilder = true) +@AllArgsConstructor +@NoArgsConstructor +public class NewApiMetadata { + + String apiId; + String key; + String name; + + @Builder.Default + Metadata.MetadataFormat format = Metadata.MetadataFormat.STRING; + + String value; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCase.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCase.java new file mode 100644 index 00000000000..d1929fd414d --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCase.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.use_case; + +import io.gravitee.apim.core.UseCase; +import io.gravitee.apim.core.api.crud_service.ApiCrudService; +import io.gravitee.apim.core.api.domain_service.ApiMetadataDomainService; +import io.gravitee.apim.core.api.domain_service.ValidateApiMetadataDomainService; +import io.gravitee.apim.core.api.exception.ApiNotFoundException; +import io.gravitee.apim.core.api.model.ApiMetadata; +import io.gravitee.apim.core.api.model.NewApiMetadata; +import io.gravitee.apim.core.audit.model.AuditInfo; + +@UseCase +public class CreateApiMetadataUseCase { + + private final ValidateApiMetadataDomainService validateApiMetadataDomainService; + private final ApiMetadataDomainService apiMetadataDomainService; + private final ApiCrudService apiCrudService; + + public CreateApiMetadataUseCase( + ValidateApiMetadataDomainService validateApiMetadataDomainService, + ApiMetadataDomainService apiMetadataDomainService, + ApiCrudService apiCrudService + ) { + this.validateApiMetadataDomainService = validateApiMetadataDomainService; + this.apiMetadataDomainService = apiMetadataDomainService; + this.apiCrudService = apiCrudService; + } + + public Output execute(Input input) { + var apiId = input.newApiMetadata.getApiId(); + + // Check that api exists with env id + var api = apiCrudService.get(apiId); + + if (!api.getEnvironmentId().equals(input.auditInfo().environmentId())) { + throw new ApiNotFoundException(apiId); + } + + this.validateApiMetadataDomainService.validateUniqueKey(apiId, input.newApiMetadata.getKey()); + this.validateApiMetadataDomainService.validateUniqueName(apiId, input.newApiMetadata.getName()); + this.validateApiMetadataDomainService.validateValueByFormat( + api, + input.auditInfo().organizationId(), + input.newApiMetadata.getValue(), + input.newApiMetadata.getFormat() + ); + + return new Output(this.apiMetadataDomainService.create(input.newApiMetadata(), input.auditInfo())); + } + + public record Input(NewApiMetadata newApiMetadata, AuditInfo auditInfo) {} + + public record Output(ApiMetadata created) {} +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/model/ApiFreemarkerTemplate.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/model/ApiFreemarkerTemplate.java index 577bb49d3f1..b304c4a20b5 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/model/ApiFreemarkerTemplate.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/documentation/model/ApiFreemarkerTemplate.java @@ -22,11 +22,12 @@ import io.gravitee.definition.model.v4.ApiType; import java.util.*; import lombok.*; +import lombok.experimental.SuperBuilder; @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder public class ApiFreemarkerTemplate { private String id; diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/crud_service/MetadataCrudService.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/crud_service/MetadataCrudService.java index ffee1d926ff..7a2a03008c7 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/crud_service/MetadataCrudService.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/crud_service/MetadataCrudService.java @@ -16,7 +16,10 @@ package io.gravitee.apim.core.metadata.crud_service; import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.metadata.model.MetadataId; +import java.util.Optional; public interface MetadataCrudService { Metadata create(Metadata metadata); + Optional findById(MetadataId id); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/model/MetadataId.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/model/MetadataId.java new file mode 100644 index 00000000000..33fc771f012 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/core/metadata/model/MetadataId.java @@ -0,0 +1,28 @@ +/* + * 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.metadata.model; + +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +public class MetadataId { + + private String key; + private Metadata.ReferenceType referenceType; + private String referenceId; +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImpl.java index d0f6d67786f..ee611ef0606 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImpl.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImpl.java @@ -18,13 +18,18 @@ import io.gravitee.apim.core.exception.TechnicalDomainException; import io.gravitee.apim.core.metadata.crud_service.MetadataCrudService; import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.metadata.model.MetadataId; import io.gravitee.apim.infra.adapter.MetadataAdapter; import io.gravitee.repository.exceptions.TechnicalException; import io.gravitee.repository.management.api.MetadataRepository; +import io.gravitee.repository.management.model.MetadataReferenceType; +import java.util.Optional; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @Service +@Slf4j public class MetadataCrudServiceImpl implements MetadataCrudService { private final MetadataRepository metadataRepository; @@ -49,4 +54,23 @@ public Metadata create(Metadata metadata) { ); } } + + @Override + public Optional findById(MetadataId id) { + try { + return metadataRepository + .findById(id.getKey(), id.getReferenceId(), MetadataReferenceType.valueOf(id.getReferenceType().name())) + .map(MetadataAdapter.INSTANCE::toEntity); + } catch (TechnicalException e) { + throw new TechnicalDomainException( + String.format( + "An error occurred while finding metadata by id [%s, %s, %s]", + id.getReferenceId(), + id.getReferenceType().name(), + id.getKey() + ), + e + ); + } + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/ApiMetadataDomainServiceLegacyWrapper.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/ApiMetadataDomainServiceLegacyWrapper.java index b0e193b9139..94314fb7c3e 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/ApiMetadataDomainServiceLegacyWrapper.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/domain_service/api/ApiMetadataDomainServiceLegacyWrapper.java @@ -20,6 +20,7 @@ import io.gravitee.apim.core.audit.domain_service.AuditDomainService; import io.gravitee.apim.core.audit.model.AuditInfo; import io.gravitee.apim.core.metadata.crud_service.MetadataCrudService; +import io.gravitee.rest.api.model.MetadataFormat; import io.gravitee.rest.api.model.UpdateApiMetadataEntity; import io.gravitee.rest.api.service.ApiMetadataService; import io.gravitee.rest.api.service.common.ExecutionContext; @@ -55,7 +56,7 @@ public void saveApiMetadata(String apiId, List metadata, AuditInfo UpdateApiMetadataEntity updateApiMetadataEntity = new UpdateApiMetadataEntity(); updateApiMetadataEntity.setApiId(apiId); updateApiMetadataEntity.setDefaultValue(apiMetadata.getDefaultValue()); - updateApiMetadataEntity.setFormat(apiMetadata.getFormat()); + updateApiMetadataEntity.setFormat(MetadataFormat.valueOf(apiMetadata.getFormat().name())); updateApiMetadataEntity.setKey(apiMetadata.getKey()); updateApiMetadataEntity.setName(apiMetadata.getName()); updateApiMetadataEntity.setValue(apiMetadata.getValue()); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/notification/internal/TemplateDataFetcher.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/notification/internal/TemplateDataFetcher.java index a0a8b83fc49..0dcdf362806 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/notification/internal/TemplateDataFetcher.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/notification/internal/TemplateDataFetcher.java @@ -17,7 +17,7 @@ import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService; import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.ApiMetadataDecodeContext; -import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.PrimaryOwnerMetadataDecodeContext; +import io.gravitee.apim.core.documentation.model.PrimaryOwnerApiTemplateData; import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; import io.gravitee.apim.core.membership.domain_service.ApplicationPrimaryOwnerDomainService; import io.gravitee.apim.core.notification.model.ApiNotificationTemplateData; @@ -117,7 +117,7 @@ private Optional buildApiNotificationTemplateData(S .createdAt(api.getCreatedAt()) .updatedAt(api.getUpdatedAt()) .primaryOwner( - new PrimaryOwnerMetadataDecodeContext( + new PrimaryOwnerApiTemplateData( apiPrimaryOwner.id(), apiPrimaryOwner.displayName(), apiPrimaryOwner.email(), diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImpl.java index 2f2b47c5af7..6fa3a23264e 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImpl.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImpl.java @@ -19,6 +19,7 @@ import io.gravitee.apim.core.api.model.ApiMetadata; import io.gravitee.apim.core.api.query_service.ApiMetadataQueryService; +import io.gravitee.apim.core.metadata.model.Metadata; import io.gravitee.repository.exceptions.TechnicalException; import io.gravitee.repository.management.api.MetadataRepository; import io.gravitee.repository.management.model.MetadataReferenceType; @@ -52,7 +53,7 @@ public Map findApiMetadata(String apiId) { .key(m.getKey()) .defaultValue(m.getValue()) .name(m.getName()) - .format(MetadataFormat.valueOf(m.getFormat().name())) + .format(Metadata.MetadataFormat.valueOf(m.getFormat().name())) .build() ) .collect(toMap(ApiMetadata::getKey, Function.identity())); @@ -73,7 +74,7 @@ public Map findApiMetadata(String apiId) { .key(m.getKey()) .value(m.getValue()) .name(m.getName()) - .format(MetadataFormat.valueOf(m.getFormat().name())) + .format(Metadata.MetadataFormat.valueOf(m.getFormat().name())) .build() ) ) diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/search/SearchEngineServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/search/SearchEngineServiceImpl.java index 051a70b529b..ac74497c1d4 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/search/SearchEngineServiceImpl.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/search/SearchEngineServiceImpl.java @@ -22,6 +22,7 @@ import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.ApiMetadataDecodeContext; import io.gravitee.apim.core.api.query_service.ApiQueryService; import io.gravitee.apim.core.documentation.crud_service.PageCrudService; +import io.gravitee.apim.core.documentation.model.PrimaryOwnerApiTemplateData; import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; import io.gravitee.apim.core.search.model.IndexableApi; import io.gravitee.apim.core.search.model.IndexablePage; @@ -211,7 +212,7 @@ private Indexable getSource(final ExecutionContext executionContext, String claz .createdAt(Date.from(api.getCreatedAt().toInstant())) .updatedAt(Date.from(api.getUpdatedAt().toInstant())) .primaryOwner( - new ApiMetadataDecoderDomainService.PrimaryOwnerMetadataDecodeContext( + new PrimaryOwnerApiTemplateData( primaryOwner.id(), primaryOwner.displayName(), primaryOwner.email(), diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/architecture/CoreRulesTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/architecture/CoreRulesTest.java index 6538a159013..b31e9fa1d72 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/architecture/CoreRulesTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/architecture/CoreRulesTest.java @@ -42,8 +42,7 @@ public void core_should_be_independent() { "org.slf4j..", "lombok..", "com.fasterxml..", - // Allow Spring transactional annotations until we find another way - "org.springframework.transaction.annotation..", + "jakarta..", // Api Definition can't be in core because it is required for the Gateway "io.gravitee.definition..", // Allow Gravitee node API to be used in core diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/MetadataFixtures.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/MetadataFixtures.java index 79afbacf7fd..939516a446b 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/MetadataFixtures.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/fixtures/core/model/MetadataFixtures.java @@ -55,7 +55,7 @@ public static ApiMetadata anApiMetadata( .value(value) .defaultValue(defaultValue) .name(name) - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build(); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/ApiMetadataQueryServiceInMemory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/ApiMetadataQueryServiceInMemory.java index 5b323a74011..181e2177df0 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/ApiMetadataQueryServiceInMemory.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/ApiMetadataQueryServiceInMemory.java @@ -51,7 +51,7 @@ public Map findApiMetadata(String apiId) { .key(m.getKey()) .name(m.getName()) .defaultValue(m.getValue()) - .format(MetadataFormat.valueOf(m.getFormat().name())) + .format(Metadata.MetadataFormat.valueOf(m.getFormat().name())) .build() ) .collect(toMap(ApiMetadata::getKey, Function.identity())); @@ -68,16 +68,7 @@ public Map findApiMetadata(String apiId) { Optional .ofNullable(existing) .map(value -> value.toBuilder().apiId(apiId).name(m.getName()).value(m.getValue()).build()) - .orElse( - ApiMetadata - .builder() - .apiId(m.getReferenceId()) - .key(m.getKey()) - .name(m.getName()) - .value(m.getValue()) - .format(MetadataFormat.valueOf(m.getFormat().name())) - .build() - ) + .orElse(this.toApiMetadata(m)) ) ); @@ -104,4 +95,15 @@ public void reset() { public List storage() { return storage; } + + private ApiMetadata toApiMetadata(Metadata metadata) { + return ApiMetadata + .builder() + .apiId(metadata.getReferenceId()) + .key(metadata.getKey()) + .name(metadata.getName()) + .value(metadata.getValue()) + .format(metadata.getFormat()) + .build(); + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/MetadataCrudServiceInMemory.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/MetadataCrudServiceInMemory.java index 67579198a37..4a71aaa33b8 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/MetadataCrudServiceInMemory.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/MetadataCrudServiceInMemory.java @@ -17,12 +17,13 @@ import io.gravitee.apim.core.metadata.crud_service.MetadataCrudService; import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.metadata.model.MetadataId; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import org.springframework.stereotype.Service; -@Service public class MetadataCrudServiceInMemory implements MetadataCrudService, InMemoryAlternative { final ArrayList storage = new ArrayList<>(); @@ -33,6 +34,18 @@ public Metadata create(Metadata entity) { return entity; } + @Override + public Optional findById(MetadataId id) { + return storage + .stream() + .filter(m -> + m.getKey().equals(id.getKey()) && + m.getReferenceId().equals(id.getReferenceId()) && + m.getReferenceType().equals(id.getReferenceType()) + ) + .findFirst(); + } + @Override public void initWith(List items) { storage.addAll(items); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java index 8cdaee96b74..d7723d54d97 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/inmemory/spring/InMemoryConfiguration.java @@ -238,4 +238,9 @@ public IntegrationCrudServiceInMemory integrationCrudService() { public IntegrationQueryServiceInMemory integrationQueryService(IntegrationCrudServiceInMemory integrationCrudServiceInMemory) { return new IntegrationQueryServiceInMemory(integrationCrudServiceInMemory); } + + @Bean + public MetadataCrudServiceInMemory metadataCrudService() { + return new MetadataCrudServiceInMemory(); + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainServiceTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainServiceTest.java index 0625af3327d..770a10b2113 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainServiceTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ApiMetadataDecoderDomainServiceTest.java @@ -19,10 +19,10 @@ import inmemory.ApiMetadataQueryServiceInMemory; import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.ApiMetadataDecodeContext; -import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService.PrimaryOwnerMetadataDecodeContext; import io.gravitee.apim.core.api.model.ApiMetadata; +import io.gravitee.apim.core.documentation.model.PrimaryOwnerApiTemplateData; +import io.gravitee.apim.core.metadata.model.Metadata; import io.gravitee.apim.infra.template.FreemarkerTemplateProcessor; -import io.gravitee.rest.api.model.MetadataFormat; import java.sql.Date; import java.time.Instant; import java.util.List; @@ -40,9 +40,7 @@ class ApiMetadataDecoderDomainServiceTest { .description("api-description") .createdAt(Date.from(Instant.parse("2020-02-01T20:22:02.00Z"))) .updatedAt(Date.from(Instant.parse("2020-02-02T20:22:02.00Z"))) - .primaryOwner( - PrimaryOwnerMetadataDecodeContext.builder().displayName("Jane Doe").email("jane.doe@gravitee.io").type("USER").build() - ) + .primaryOwner(PrimaryOwnerApiTemplateData.builder().displayName("Jane Doe").email("jane.doe@gravitee.io").type("USER").build()) .build(); ApiMetadataQueryServiceInMemory apiMetadataQueryService = new ApiMetadataQueryServiceInMemory(); @@ -59,8 +57,8 @@ public void should_return_simple_metadata() { // Given givenExistingApiMetadata( List.of( - ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(MetadataFormat.STRING).build(), - ApiMetadata.builder().apiId(API_ID).key("key2").value("true").format(MetadataFormat.BOOLEAN).build() + ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(Metadata.MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("key2").value("true").format(Metadata.MetadataFormat.BOOLEAN).build() ) ); @@ -76,8 +74,8 @@ public void should_filter_metadata_with_null_value() { // Given givenExistingApiMetadata( List.of( - ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(MetadataFormat.STRING).build(), - ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(MetadataFormat.STRING).build() + ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(Metadata.MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(Metadata.MetadataFormat.STRING).build() ) ); @@ -93,27 +91,27 @@ public void should_decode_metadata_having_el() { // Given givenExistingApiMetadata( List.of( - ApiMetadata.builder().apiId(API_ID).key("apiName").value("${(api.name)!''}").format(MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("apiName").value("${(api.name)!''}").format(Metadata.MetadataFormat.STRING).build(), ApiMetadata .builder() .apiId(API_ID) .key("apiDescription") .value("${(api.description)!''}") - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build(), ApiMetadata .builder() .apiId(API_ID) .key("ownerName") .value("${(api.primaryOwner.displayName)!''}") - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build(), ApiMetadata .builder() .apiId(API_ID) .key("email-support") .value("${(api.primaryOwner.email)!''}") - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build() ) ); @@ -138,8 +136,8 @@ public void should_return_raw_metadata_when_one_of_them_has_invalid_el() { // Given givenExistingApiMetadata( List.of( - ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(MetadataFormat.STRING).build(), - ApiMetadata.builder().apiId(API_ID).key("apiVersion").value("${api.version}").format(MetadataFormat.STRING).build() + ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(Metadata.MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("apiVersion").value("${api.version}").format(Metadata.MetadataFormat.STRING).build() ) ); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainServiceTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainServiceTest.java new file mode 100644 index 00000000000..dece7ccf10c --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/domain_service/ValidateApiMetadataDomainServiceTest.java @@ -0,0 +1,193 @@ +/* + * 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.domain_service; + +import static org.assertj.core.api.Assertions.*; + +import inmemory.*; +import io.gravitee.apim.core.api.exception.InvalidApiMetadataValueException; +import io.gravitee.apim.core.api.model.Api; +import io.gravitee.apim.core.audit.domain_service.AuditDomainService; +import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; +import io.gravitee.apim.core.membership.model.Membership; +import io.gravitee.apim.core.membership.model.Role; +import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.user.model.BaseUserEntity; +import io.gravitee.apim.infra.json.jackson.JacksonJsonDiffProcessor; +import io.gravitee.apim.infra.template.FreemarkerTemplateProcessor; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ValidateApiMetadataDomainServiceTest { + + private static final String API_ID = "my-api"; + private static final String ORGANIZATION_ID = "organization-id"; + AuditCrudServiceInMemory auditCrudService = new AuditCrudServiceInMemory(); + UserCrudServiceInMemory userCrudService = new UserCrudServiceInMemory(); + GroupQueryServiceInMemory groupQueryService = new GroupQueryServiceInMemory(); + MembershipCrudServiceInMemory membershipCrudService = new MembershipCrudServiceInMemory(); + MembershipQueryServiceInMemory membershipQueryService = new MembershipQueryServiceInMemory(membershipCrudService); + RoleQueryServiceInMemory roleQueryService = new RoleQueryServiceInMemory(); + MetadataCrudServiceInMemory metadataCrudService = new MetadataCrudServiceInMemory(); + ApiMetadataQueryServiceInMemory apiMetadataQueryService; + ValidateApiMetadataDomainService service; + + @BeforeEach + void setUp() { + var auditDomainService = new AuditDomainService(auditCrudService, userCrudService, new JacksonJsonDiffProcessor()); + var apiMetadataDecoderDomainService = new ApiMetadataDecoderDomainService( + apiMetadataQueryService, + new FreemarkerTemplateProcessor() + ); + service = + new ValidateApiMetadataDomainService( + apiMetadataQueryService, + metadataCrudService, + new ApiPrimaryOwnerDomainService( + auditDomainService, + groupQueryService, + membershipCrudService, + membershipQueryService, + roleQueryService, + userCrudService + ), + apiMetadataDecoderDomainService + ); + + roleQueryService.initWith( + List.of( + Role + .builder() + .id("role-id") + .scope(Role.Scope.API) + .referenceType(Role.ReferenceType.ORGANIZATION) + .referenceId(ORGANIZATION_ID) + .name("PRIMARY_OWNER") + .build() + ) + ); + membershipQueryService.initWith( + List.of( + Membership + .builder() + .id("member-id") + .memberId("my-member-id") + .memberType(Membership.Type.USER) + .referenceType(Membership.ReferenceType.API) + .referenceId(API_ID) + .roleId("role-id") + .build() + ) + ); + userCrudService.initWith(List.of(BaseUserEntity.builder().id("my-member-id").email("one_valid@email.com").build())); + + metadataCrudService.initWith( + List.of( + Metadata.builder().referenceId(API_ID).referenceType(Metadata.ReferenceType.API).key("exists").value("john@doe.com").build() + ) + ); + } + + @AfterEach + void tearDown() { + Stream + .of( + auditCrudService, + membershipCrudService, + roleQueryService, + userCrudService, + metadataCrudService, + groupQueryService, + membershipQueryService + ) + .forEach(InMemoryAlternative::reset); + } + + @Nested + class ValidateValueByFormat { + + @ParameterizedTest + @MethodSource("provideValidParameters") + void should_validate_value(final String value, final Metadata.MetadataFormat format) { + assertThatCode(() -> service.validateValueByFormat(Api.builder().build(), ORGANIZATION_ID, value, format)) + .doesNotThrowAnyException(); + } + + public static Stream provideValidParameters() { + return Stream.of( + Arguments.of("john@doe.com", Metadata.MetadataFormat.MAIL), + Arguments.of("https://my-url.com", Metadata.MetadataFormat.URL), + Arguments.of("https://my-url", Metadata.MetadataFormat.URL), + Arguments.of("2005-01-01", Metadata.MetadataFormat.DATE), + Arguments.of("2021-10-06T15:17:15.282+00:00", Metadata.MetadataFormat.DATE), + Arguments.of("42", Metadata.MetadataFormat.NUMERIC), + Arguments.of("100.5", Metadata.MetadataFormat.NUMERIC), + Arguments.of("true", Metadata.MetadataFormat.BOOLEAN), + Arguments.of("false", Metadata.MetadataFormat.BOOLEAN), + Arguments.of("any value for boolean works", Metadata.MetadataFormat.BOOLEAN), + Arguments.of("100", Metadata.MetadataFormat.STRING) + ); + } + + @ParameterizedTest + @MethodSource("provideInvalidParameters") + void should_throw_error_on_invalid_value(final String value, final Metadata.MetadataFormat format) { + assertThatThrownBy(() -> service.validateValueByFormat(Api.builder().id(API_ID).build(), ORGANIZATION_ID, value, format)) + .isInstanceOf(InvalidApiMetadataValueException.class); + } + + public static Stream provideInvalidParameters() { + return Stream.of( + Arguments.of("johndoe.com", Metadata.MetadataFormat.MAIL), + Arguments.of("@johndoe.com", Metadata.MetadataFormat.MAIL), + Arguments.of("my-url", Metadata.MetadataFormat.URL), + Arguments.of("my-url.com", Metadata.MetadataFormat.URL), + Arguments.of("2005", Metadata.MetadataFormat.DATE), + Arguments.of("1/2", Metadata.MetadataFormat.NUMERIC) + ); + } + } + + @Test + void should_throw_error_when_decoding_mail_value_referencing_another_metadata_key() { + assertThatThrownBy(() -> + service.validateValueByFormat( + Api.builder().id(API_ID).build(), + ORGANIZATION_ID, + "${api.metadata['exists']}", + Metadata.MetadataFormat.MAIL + ) + ) + .isInstanceOf(InvalidApiMetadataValueException.class); + } + + @Test + void should_not_throw_error_when_decoding_string_value_referencing_another_metadata_key() { + assertThatCode(() -> + service.validateValueByFormat( + Api.builder().id(API_ID).build(), + ORGANIZATION_ID, + "${api.metadata['exists']}", + Metadata.MetadataFormat.STRING + ) + ) + .doesNotThrowAnyException(); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCaseTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCaseTest.java new file mode 100644 index 00000000000..7d048aa4d15 --- /dev/null +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/core/api/use_case/CreateApiMetadataUseCaseTest.java @@ -0,0 +1,386 @@ +/* + * 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.use_case; + +import static fixtures.core.model.ApiFixtures.aMessageApiV4; +import static fixtures.core.model.MetadataFixtures.anApiMetadata; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import inmemory.*; +import io.gravitee.apim.core.api.domain_service.ApiMetadataDecoderDomainService; +import io.gravitee.apim.core.api.domain_service.ApiMetadataDomainService; +import io.gravitee.apim.core.api.domain_service.ValidateApiMetadataDomainService; +import io.gravitee.apim.core.api.exception.ApiNotFoundException; +import io.gravitee.apim.core.api.exception.DuplicateApiMetadataKeyException; +import io.gravitee.apim.core.api.exception.DuplicateApiMetadataNameException; +import io.gravitee.apim.core.api.exception.InvalidApiMetadataValueException; +import io.gravitee.apim.core.api.model.Api; +import io.gravitee.apim.core.api.model.ApiMetadata; +import io.gravitee.apim.core.api.model.NewApiMetadata; +import io.gravitee.apim.core.audit.domain_service.AuditDomainService; +import io.gravitee.apim.core.audit.model.AuditActor; +import io.gravitee.apim.core.audit.model.AuditInfo; +import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; +import io.gravitee.apim.core.membership.model.Membership; +import io.gravitee.apim.core.membership.model.Role; +import io.gravitee.apim.core.metadata.model.Metadata; +import io.gravitee.apim.core.user.model.BaseUserEntity; +import io.gravitee.apim.infra.json.jackson.JacksonJsonDiffProcessor; +import io.gravitee.apim.infra.template.FreemarkerTemplateProcessor; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.*; + +@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) +public class CreateApiMetadataUseCaseTest { + + private final String API_ID = "api-id"; + private final String ORG_ID = "org-id"; + private final String ENV_ID = "env-id"; + private final AuditInfo AUDIT_INFO = AuditInfo + .builder() + .organizationId(ORG_ID) + .environmentId(ENV_ID) + .actor(AuditActor.builder().userId("user").build()) + .build(); + private final Api API = aMessageApiV4().toBuilder().id(API_ID).environmentId(ENV_ID).build(); + private final ApiCrudServiceInMemory apiCrudService = new ApiCrudServiceInMemory(); + AuditCrudServiceInMemory auditCrudService = new AuditCrudServiceInMemory(); + GroupQueryServiceInMemory groupQueryService = new GroupQueryServiceInMemory(); + MembershipCrudServiceInMemory membershipCrudService = new MembershipCrudServiceInMemory(); + MembershipQueryServiceInMemory membershipQueryService = new MembershipQueryServiceInMemory(membershipCrudService); + RoleQueryServiceInMemory roleQueryService = new RoleQueryServiceInMemory(); + UserCrudServiceInMemory userCrudService = new UserCrudServiceInMemory(); + private final MetadataCrudServiceInMemory metadataCrudServiceInMemory = new MetadataCrudServiceInMemory(); + private ApiMetadataQueryServiceInMemory apiMetadataQueryService; + private CreateApiMetadataUseCase createApiMetadataUseCase; + + @BeforeEach + void setUp() { + apiMetadataQueryService = new ApiMetadataQueryServiceInMemory(metadataCrudServiceInMemory); + + var auditDomainService = new AuditDomainService(auditCrudService, userCrudService, new JacksonJsonDiffProcessor()); + var apiMetadataDecoderDomainService = new ApiMetadataDecoderDomainService( + apiMetadataQueryService, + new FreemarkerTemplateProcessor() + ); + var validateApiMetadataDomainService = new ValidateApiMetadataDomainService( + apiMetadataQueryService, + metadataCrudServiceInMemory, + new ApiPrimaryOwnerDomainService( + auditDomainService, + groupQueryService, + membershipCrudService, + membershipQueryService, + roleQueryService, + userCrudService + ), + apiMetadataDecoderDomainService + ); + var apiMetadataDomainService = new ApiMetadataDomainService(metadataCrudServiceInMemory, auditDomainService); + createApiMetadataUseCase = new CreateApiMetadataUseCase(validateApiMetadataDomainService, apiMetadataDomainService, apiCrudService); + + apiCrudService.initWith(List.of(API)); + this.initializePrimaryOwnerData(); + } + + @AfterEach + void tearDown() { + Stream + .of( + auditCrudService, + membershipCrudService, + roleQueryService, + userCrudService, + metadataCrudServiceInMemory, + apiMetadataQueryService, + apiCrudService, + groupQueryService, + membershipQueryService + ) + .forEach(InMemoryAlternative::reset); + } + + @Test + void creates_api_metadata() { + var expected = ApiMetadata + .builder() + .apiId(API_ID) + .name("name") + .value("value") + .key("key") + .format(Metadata.MetadataFormat.STRING) + .build(); + var createdMetadata = createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ); + assertThat(createdMetadata.created()).isNotNull(); + assertThat(createdMetadata.created()).usingRecursiveComparison().isEqualTo(expected); + } + + @Test + void creates_api_metadata_overriding_global_metadata() { + apiMetadataQueryService.initWith( + List.of( + Metadata + .builder() + .referenceId("_") + .referenceType(Metadata.ReferenceType.DEFAULT) + .name("global name") + .key("key") + .value("old-value") + .format(Metadata.MetadataFormat.STRING) + .build() + ) + ); + var expected = ApiMetadata + .builder() + .apiId(API_ID) + .name("name") + .value("value") + .defaultValue("old-value") + .key("key") + .format(Metadata.MetadataFormat.STRING) + .build(); + var createdMetadata = createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ); + assertThat(createdMetadata.created()).isNotNull(); + assertThat(createdMetadata.created()).usingRecursiveComparison().isEqualTo(expected); + } + + @Test + void cannot_create_if_api_not_in_env() { + apiCrudService.reset(); + assertThrows( + ApiNotFoundException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void cannot_create_with_duplicate_key() { + apiMetadataQueryService.initWithApiMetadata( + List.of(ApiMetadata.builder().apiId(API_ID).key("key").format(Metadata.MetadataFormat.STRING).build()) + ); + assertThrows( + DuplicateApiMetadataKeyException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void cannot_create_with_duplicate_api_metadata_name() { + apiMetadataQueryService.initWith( + List.of( + Metadata + .builder() + .name("name") + .key("key") + .referenceId(API_ID) + .referenceType(Metadata.ReferenceType.API) + .format(Metadata.MetadataFormat.STRING) + .build() + ) + ); + assertThrows( + DuplicateApiMetadataNameException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("new key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void cannot_create_with_duplicate_global_metadata_name() { + apiMetadataQueryService.initWith( + List.of( + Metadata + .builder() + .name("nAmE") + .key("key") + .referenceId("_") + .referenceType(Metadata.ReferenceType.DEFAULT) + .format(Metadata.MetadataFormat.STRING) + .build() + ) + ); + assertThrows( + DuplicateApiMetadataNameException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("new key") + .name("name") + .value("value") + .format(Metadata.MetadataFormat.STRING) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void error_if_value_does_not_match_format() { + assertThrows( + InvalidApiMetadataValueException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("new key") + .name("name") + .value("not an email") + .format(Metadata.MetadataFormat.MAIL) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void error_if_value_with_template_does_not_match_format() { + assertThrows( + InvalidApiMetadataValueException.class, + () -> + createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("new key") + .name("name") + .value("${api.version}") + .format(Metadata.MetadataFormat.MAIL) + .build(), + AUDIT_INFO + ) + ) + ); + } + + @Test + void can_create_with_templated_value() { + var createdApiMetadata = createApiMetadataUseCase.execute( + new CreateApiMetadataUseCase.Input( + NewApiMetadata + .builder() + .apiId(API_ID) + .key("new key") + .name("name") + .value("${api.primaryOwner.email}") + .format(Metadata.MetadataFormat.MAIL) + .build(), + AUDIT_INFO + ) + ); + assertThat(createdApiMetadata).isNotNull(); + } + + private void initializePrimaryOwnerData() { + roleQueryService.initWith( + List.of( + Role + .builder() + .id("role-id") + .scope(Role.Scope.API) + .referenceType(Role.ReferenceType.ORGANIZATION) + .referenceId(ORG_ID) + .name("PRIMARY_OWNER") + .build() + ) + ); + membershipQueryService.initWith( + List.of( + Membership + .builder() + .id("member-id") + .memberId("my-member-id") + .memberType(Membership.Type.USER) + .referenceType(Membership.ReferenceType.API) + .referenceId(API_ID) + .roleId("role-id") + .build() + ) + ); + userCrudService.initWith(List.of(BaseUserEntity.builder().id("my-member-id").email("one_valid@email.com").build())); + } +} diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImplTest.java index 3122f5fa09f..2b3b138ae15 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImplTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/crud_service/metadata/MetadataCrudServiceImplTest.java @@ -24,11 +24,15 @@ import fixtures.core.model.MetadataFixtures; import io.gravitee.apim.core.exception.TechnicalDomainException; +import io.gravitee.apim.core.metadata.model.MetadataId; import io.gravitee.repository.exceptions.TechnicalException; import io.gravitee.repository.management.api.MetadataRepository; +import io.gravitee.repository.management.model.Metadata; import io.gravitee.repository.management.model.MetadataFormat; +import io.gravitee.repository.management.model.MetadataReferenceType; import java.time.Instant; import java.util.Date; +import java.util.Optional; import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -101,4 +105,59 @@ void should_throw_when_technical_exception_occurs() throws TechnicalException { .hasMessage("An error occurs while trying to create the my-key metadata of [apiId=api-id]"); } } + + @Nested + class FindById { + + @Test + void should_find_metadata_by_id() throws TechnicalException { + when(metadataRepository.findById("key", "referenceId", MetadataReferenceType.API)) + .thenReturn( + Optional.of( + Metadata + .builder() + .key("key") + .referenceId("referenceId") + .referenceType(MetadataReferenceType.API) + .value("value") + .build() + ) + ); + + var foundMetadata = service.findById( + MetadataId + .builder() + .key("key") + .referenceId("referenceId") + .referenceType(io.gravitee.apim.core.metadata.model.Metadata.ReferenceType.API) + .build() + ); + + assertThat(foundMetadata).isPresent(); + assertThat(foundMetadata) + .hasValue( + io.gravitee.apim.core.metadata.model.Metadata + .builder() + .referenceType(io.gravitee.apim.core.metadata.model.Metadata.ReferenceType.API) + .referenceId("referenceId") + .key("key") + .value("value") + .build() + ); + } + + @Test + void should_not_find_metadata_by_id_if_missing() { + var foundMetadata = service.findById( + MetadataId + .builder() + .key("key") + .referenceId("referenceId") + .referenceType(io.gravitee.apim.core.metadata.model.Metadata.ReferenceType.API) + .build() + ); + + assertThat(foundMetadata).isEmpty(); + } + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/notification/TriggerNotificationDomainServiceFacadeImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/notification/TriggerNotificationDomainServiceFacadeImplTest.java index b11d4261a07..3e5fbf1a347 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/notification/TriggerNotificationDomainServiceFacadeImplTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/notification/TriggerNotificationDomainServiceFacadeImplTest.java @@ -38,6 +38,7 @@ import io.gravitee.apim.core.membership.domain_service.ApiPrimaryOwnerDomainService; import io.gravitee.apim.core.membership.domain_service.ApplicationPrimaryOwnerDomainService; import io.gravitee.apim.core.membership.model.PrimaryOwnerEntity; +import io.gravitee.apim.core.metadata.model.Metadata; import io.gravitee.apim.core.notification.domain_service.TriggerNotificationDomainService; import io.gravitee.apim.core.notification.model.ApiNotificationTemplateData; import io.gravitee.apim.core.notification.model.ApplicationNotificationTemplateData; @@ -222,14 +223,14 @@ public void should_fetch_api_notification_data_with_metadata() { anApi().withId(API_ID), PrimaryOwnerEntity.builder().id(USER_ID).build(), List.of( - ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(MetadataFormat.STRING).build(), - ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(Metadata.MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(Metadata.MetadataFormat.STRING).build(), ApiMetadata .builder() .apiId(API_ID) .key("email-support") .value("${(api.primaryOwner.email)!''}") - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build() ) ); @@ -629,14 +630,14 @@ public void should_fetch_api_notification_data_with_metadata() { anApi().withId(API_ID), PrimaryOwnerEntity.builder().id(USER_ID).build(), List.of( - ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(MetadataFormat.STRING).build(), - ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("key1").value("value1").format(Metadata.MetadataFormat.STRING).build(), + ApiMetadata.builder().apiId(API_ID).key("null_key").value(null).format(Metadata.MetadataFormat.STRING).build(), ApiMetadata .builder() .apiId(API_ID) .key("email-support") .value("${(api.primaryOwner.email)!''}") - .format(MetadataFormat.STRING) + .format(Metadata.MetadataFormat.STRING) .build() ) ); diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImplTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImplTest.java index 09d4db37c0b..9d42c30205a 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImplTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/apim/infra/query_service/api/ApiMetadataQueryServiceImplTest.java @@ -85,11 +85,23 @@ void should_return_api_metadata() { .hasSize(2) .containsEntry( "team-contact", - ApiMetadata.builder().apiId(API_ID).key("team-contact").value("team@gravitee.io").format(MetadataFormat.MAIL).build() + ApiMetadata + .builder() + .apiId(API_ID) + .key("team-contact") + .value("team@gravitee.io") + .format(io.gravitee.apim.core.metadata.model.Metadata.MetadataFormat.MAIL) + .build() ) .containsEntry( "homepage", - ApiMetadata.builder().apiId(API_ID).key("homepage").value("https://gravitee.io").format(MetadataFormat.URL).build() + ApiMetadata + .builder() + .apiId(API_ID) + .key("homepage") + .value("https://gravitee.io") + .format(io.gravitee.apim.core.metadata.model.Metadata.MetadataFormat.URL) + .build() ); } @@ -137,14 +149,28 @@ void should_return_api_metadata_with_their_default_value() { .key("team-contact") .value("team@gravitee.io") .defaultValue("admin@gravitee.io") - .format(MetadataFormat.MAIL) + .format(io.gravitee.apim.core.metadata.model.Metadata.MetadataFormat.MAIL) .build() ) .containsEntry( "homepage", - ApiMetadata.builder().apiId(API_ID).key("homepage").value("https://gravitee.io").format(MetadataFormat.URL).build() + ApiMetadata + .builder() + .apiId(API_ID) + .key("homepage") + .value("https://gravitee.io") + .format(io.gravitee.apim.core.metadata.model.Metadata.MetadataFormat.URL) + .build() ) - .containsEntry("brand", ApiMetadata.builder().key("brand").defaultValue("Gravitee").format(MetadataFormat.STRING).build()); + .containsEntry( + "brand", + ApiMetadata + .builder() + .key("brand") + .defaultValue("Gravitee") + .format(io.gravitee.apim.core.metadata.model.Metadata.MetadataFormat.STRING) + .build() + ); } @Test