Skip to content

Commit b5b3597

Browse files
committed
feat: allow users to get subscriptions with their consumer configuration
1 parent 6a7f354 commit b5b3597

File tree

7 files changed

+187
-8
lines changed

7 files changed

+187
-8
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright © 2015 The Gravitee team (http://gravitee.io)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.gravitee.rest.api.portal.rest.mapper;
17+
18+
import com.fasterxml.jackson.core.JsonProcessingException;
19+
import com.fasterxml.jackson.databind.JsonNode;
20+
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import io.gravitee.definition.jackson.datatype.GraviteeMapper;
22+
import io.gravitee.rest.api.service.exceptions.TechnicalManagementException;
23+
import java.util.LinkedHashMap;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Objects;
27+
import org.mapstruct.Mapper;
28+
import org.mapstruct.Named;
29+
import org.mapstruct.factory.Mappers;
30+
import org.slf4j.Logger;
31+
import org.slf4j.LoggerFactory;
32+
33+
@Mapper
34+
public interface ConfigurationSerializationMapper {
35+
ConfigurationSerializationMapper INSTANCE = Mappers.getMapper(ConfigurationSerializationMapper.class);
36+
Logger logger = LoggerFactory.getLogger(ConfigurationSerializationMapper.class);
37+
38+
@Named("deserializeConfiguration")
39+
default Object deserializeConfiguration(String configuration) {
40+
if (Objects.isNull(configuration)) {
41+
return null;
42+
}
43+
44+
ObjectMapper mapper = new GraviteeMapper();
45+
try {
46+
return mapper.readValue(configuration, LinkedHashMap.class);
47+
} catch (JsonProcessingException jse) {
48+
logger.debug("Cannot parse configuration as LinkedHashMap: " + configuration);
49+
}
50+
51+
try {
52+
return mapper.readValue(configuration, List.class);
53+
} catch (JsonProcessingException jse) {
54+
logger.debug("Cannot parse configuration as List: " + configuration);
55+
}
56+
57+
return configuration;
58+
}
59+
}

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/main/java/io/gravitee/rest/api/portal/rest/mapper/SubscriptionMapper.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
*/
1616
package io.gravitee.rest.api.portal.rest.mapper;
1717

18+
import io.gravitee.rest.api.model.SubscriptionConfigurationEntity;
1819
import io.gravitee.rest.api.model.SubscriptionEntity;
1920
import io.gravitee.rest.api.model.SubscriptionStatus;
2021
import io.gravitee.rest.api.portal.rest.model.Subscription;
22+
import io.gravitee.rest.api.portal.rest.model.SubscriptionConsumerConfiguration;
2123
import org.mapstruct.Mapper;
2224
import org.mapstruct.Mapping;
2325
import org.mapstruct.factory.Mappers;
@@ -28,7 +30,7 @@
2830
* @author Florent CHAMFROY (florent.chamfroy at graviteesource.com)
2931
* @author GraviteeSource Team
3032
*/
31-
@Mapper(uses = { DateMapper.class })
33+
@Mapper(uses = { ConfigurationSerializationMapper.class, DateMapper.class })
3234
public interface SubscriptionMapper {
3335
Logger log = LoggerFactory.getLogger(SubscriptionMapper.class);
3436
SubscriptionMapper INSTANCE = Mappers.getMapper(SubscriptionMapper.class);
@@ -38,6 +40,9 @@ public interface SubscriptionMapper {
3840
@Mapping(target = "startAt", source = "startingAt")
3941
Subscription map(SubscriptionEntity subscriptionEntity);
4042

43+
@Mapping(target = "entrypointConfiguration", qualifiedByName = "deserializeConfiguration")
44+
SubscriptionConsumerConfiguration map(SubscriptionConfigurationEntity subscriptionConfigurationEntity);
45+
4146
default Subscription.StatusEnum map(SubscriptionStatus status) {
4247
return Subscription.StatusEnum.fromValue(status.name());
4348
}

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/main/java/io/gravitee/rest/api/portal/rest/resource/SubscriptionResource.java

+7
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ public class SubscriptionResource extends AbstractResource {
8484
private GraviteeMapper graviteeMapper;
8585

8686
private static final String INCLUDE_KEYS = "keys";
87+
private static final String INCLUDE_CONSUMER_CONFIGURATION = "consumerConfiguration";
8788

8889
@GET
8990
@Produces(MediaType.APPLICATION_JSON)
@@ -93,6 +94,7 @@ public Response getSubscriptionBySubscriptionId(
9394
) {
9495
SubscriptionEntity subscriptionEntity = subscriptionService.findById(subscriptionId);
9596
final ExecutionContext executionContext = GraviteeContext.getExecutionContext();
97+
9698
if (
9799
hasPermission(executionContext, RolePermission.API_SUBSCRIPTION, subscriptionEntity.getApi(), RolePermissionAction.READ) ||
98100
hasPermission(executionContext, APPLICATION_SUBSCRIPTION, subscriptionEntity.getApplication(), RolePermissionAction.READ)
@@ -107,6 +109,11 @@ public Response getSubscriptionBySubscriptionId(
107109
.collect(Collectors.toList());
108110
subscription.setKeys(keys);
109111
}
112+
113+
if (include.contains(INCLUDE_CONSUMER_CONFIGURATION)) {
114+
subscription.setConsumerConfiguration(SubscriptionMapper.INSTANCE.map(subscriptionEntity.getConfiguration()));
115+
}
116+
110117
return Response.ok(subscription).build();
111118
}
112119
throw new ForbiddenAccessException();

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/main/resources/portal-openapi.yaml

+36
Original file line numberDiff line numberDiff line change
@@ -3489,6 +3489,7 @@ components:
34893489
type: string
34903490
enum:
34913491
- keys
3492+
- consumerConfiguration
34923493
subscriptionConsumerStatusParam:
34933494
name: status
34943495
in: query
@@ -4601,6 +4602,9 @@ components:
46014602
type: array
46024603
items:
46034604
$ref: "#/components/schemas/Key"
4605+
consumerConfiguration:
4606+
$ref: "#/components/schemas/SubscriptionConsumerConfiguration"
4607+
46044608
Ticket:
46054609
properties:
46064610
id:
@@ -5934,6 +5938,38 @@ components:
59345938
type: array
59355939
items:
59365940
type: string
5941+
5942+
SubscriptionConsumerConfiguration:
5943+
type: object
5944+
description: Consumer configuration associated to the subscription in case it is attached to a push plan.
5945+
properties:
5946+
entrypointId:
5947+
type: string
5948+
description: The id of the targeted entrypoint
5949+
example: webhook
5950+
channel:
5951+
type: string
5952+
description: The channel to consume
5953+
example: /channel1
5954+
entrypointConfiguration:
5955+
type: object
5956+
description: The configuration to use at subscription time to push to the target service.
5957+
example: |
5958+
{
5959+
"callbackUrl": "https://webhook.site/aaaaaaaa-ffff-ffff-ffff-aaaaaaaa",
5960+
"headers": [
5961+
{
5962+
"name": "demoHeader",
5963+
"value": "my-value"
5964+
},
5965+
{
5966+
"name": "anotherHeader",
5967+
"value": "my-value2"
5968+
}
5969+
]
5970+
}
5971+
required: [ entrypointId ]
5972+
59375973
responses:
59385974
InternalServerError:
59395975
description: Internal Server Error

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/test/java/io/gravitee/rest/api/portal/rest/mapper/SubscriptionMapperTest.java

+34
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,22 @@
1515
*/
1616
package io.gravitee.rest.api.portal.rest.mapper;
1717

18+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
1819
import static org.junit.Assert.assertEquals;
1920
import static org.junit.Assert.assertNotNull;
2021
import static org.junit.Assert.assertNull;
2122

23+
import com.fasterxml.jackson.databind.JsonNode;
24+
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import io.gravitee.rest.api.model.SubscriptionConfigurationEntity;
2226
import io.gravitee.rest.api.model.SubscriptionEntity;
2327
import io.gravitee.rest.api.model.SubscriptionStatus;
2428
import io.gravitee.rest.api.portal.rest.model.Subscription;
2529
import io.gravitee.rest.api.portal.rest.model.Subscription.StatusEnum;
30+
import io.gravitee.rest.api.portal.rest.model.SubscriptionConsumerConfiguration;
2631
import java.time.Instant;
2732
import java.util.Date;
33+
import lombok.SneakyThrows;
2834
import org.junit.Test;
2935
import org.mapstruct.factory.Mappers;
3036

@@ -47,6 +53,7 @@ public class SubscriptionMapperTest {
4753
private SubscriptionEntity subscriptionEntity;
4854

4955
private final SubscriptionMapper subscriptionMapper = Mappers.getMapper(SubscriptionMapper.class);
56+
private final ObjectMapper objectMapper = new ObjectMapper();
5057

5158
@Test
5259
public void testConvert() {
@@ -129,4 +136,31 @@ public void should_handle_origin_not_in_enum() {
129136
assertEquals(SUBSCRIPTION_API, subscription.getApi());
130137
assertNull(subscription.getOrigin());
131138
}
139+
140+
@Test
141+
@SneakyThrows
142+
public void should_handle_entrypoint_configuration() {
143+
var entrypointId = "entrypointId";
144+
var configuration =
145+
"{\"auth\":{\"type\":\"none\"},\"callbackUrl\":\"https://webhook.example/1234\",\"ssl\":{\"keyStore\":{\"type\":\"\"},\"hostnameVerifier\":false,\"trustStore\":{\"type\":\"\"},\"trustAll\":true},\"retry\":{\"retryOption\":\"No Retry\"}}";
146+
var channel = "channel";
147+
148+
SubscriptionConfigurationEntity subscriptionConfigurationEntity = new SubscriptionConfigurationEntity();
149+
subscriptionConfigurationEntity.setEntrypointId(entrypointId);
150+
subscriptionConfigurationEntity.setChannel(channel);
151+
subscriptionConfigurationEntity.setEntrypointConfiguration(configuration);
152+
153+
SubscriptionConsumerConfiguration result = subscriptionMapper.map(subscriptionConfigurationEntity);
154+
155+
assertThat(entrypointId).isEqualTo(result.getEntrypointId());
156+
assertThat(channel).isEqualTo(result.getChannel());
157+
assertThat(result).isNotNull();
158+
assertThat(result.getEntrypointConfiguration()).isNotNull();
159+
160+
JsonNode actualConfig = objectMapper.valueToTree(result.getEntrypointConfiguration());
161+
assertThat(actualConfig.get("auth").get("type").asText()).isEqualTo("none");
162+
assertThat(actualConfig.get("callbackUrl").asText()).isEqualTo("https://webhook.example/1234");
163+
assertThat(actualConfig.get("ssl").get("trustAll").asBoolean()).isTrue();
164+
assertThat(actualConfig.get("retry").get("retryOption").asText()).isEqualTo("No Retry");
165+
}
132166
}

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/test/java/io/gravitee/rest/api/portal/rest/resource/SubscriptionResourceTest.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.junit.Before;
4141
import org.junit.Test;
4242
import org.mockito.ArgumentCaptor;
43-
import org.mockito.Mockito;
4443

4544
/**
4645
* @author Florent CHAMFROY (florent.chamfroy at graviteesource.com)
@@ -197,6 +196,41 @@ public void shouldGetSubscriptionWithKeys() {
197196
assertFalse(subscription.getKeys().isEmpty());
198197
}
199198

199+
@Test
200+
public void shouldGetSubscriptionWithConsumerStatus() {
201+
doReturn(true)
202+
.when(permissionService)
203+
.hasPermission(
204+
eq(GraviteeContext.getExecutionContext()),
205+
eq(RolePermission.API_SUBSCRIPTION),
206+
eq(API),
207+
eq(RolePermissionAction.READ)
208+
);
209+
doReturn(true)
210+
.when(permissionService)
211+
.hasPermission(
212+
eq(GraviteeContext.getExecutionContext()),
213+
eq(RolePermission.APPLICATION_SUBSCRIPTION),
214+
eq(APPLICATION),
215+
eq(RolePermissionAction.READ)
216+
);
217+
218+
SubscriptionConfigurationEntity subscriptionConfigurationEntity = new SubscriptionConfigurationEntity();
219+
subscriptionConfigurationEntity.setEntrypointId("entrypointId");
220+
subscriptionConfigurationEntity.setChannel("channel");
221+
subscriptionConfigurationEntity.setEntrypointConfiguration(
222+
"{\"auth\":{\"type\":\"none\"},\"callbackUrl\":\"https://webhook.example/1234\",\"ssl\":{\"keyStore\":{\"type\":\"\"},\"hostnameVerifier\":false,\"trustStore\":{\"type\":\"\"},\"trustAll\":true},\"retry\":{\"retryOption\":\"No Retry\"}}"
223+
);
224+
subscriptionEntity.setConfiguration(subscriptionConfigurationEntity);
225+
226+
final Response response = target(SUBSCRIPTION).queryParam("include", "consumerConfiguration").request().get();
227+
assertEquals(HttpStatusCode.OK_200, response.getStatus());
228+
229+
Subscription subscription = response.readEntity(Subscription.class);
230+
assertNotNull(subscription);
231+
assertNotNull(subscription.getConsumerConfiguration());
232+
}
233+
200234
@Test
201235
public void shouldNotGetSubscription() {
202236
final Response response = target(UNKNOWN_SUBSCRIPTION).request().get();

gravitee-apim-rest-api/gravitee-apim-rest-api-portal/gravitee-apim-rest-api-portal-rest/src/test/java/io/gravitee/rest/api/portal/rest/resource/SubscriptionsResourceTest.java

+10-6
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
import static io.gravitee.common.http.HttpStatusCode.OK_200;
2020
import static java.util.Arrays.asList;
2121
import static java.util.Collections.emptyList;
22-
import static org.junit.Assert.*;
22+
import static org.junit.Assert.assertEquals;
23+
import static org.junit.Assert.assertNotNull;
24+
import static org.junit.Assert.assertNull;
2325
import static org.mockito.ArgumentMatchers.any;
2426
import static org.mockito.ArgumentMatchers.eq;
25-
import static org.mockito.Mockito.*;
27+
import static org.mockito.Mockito.doReturn;
28+
import static org.mockito.Mockito.reset;
29+
import static org.mockito.Mockito.when;
2630
import static org.mockito.internal.util.collections.Sets.newSet;
2731

2832
import io.gravitee.common.data.domain.Page;
@@ -32,11 +36,11 @@
3236
import io.gravitee.rest.api.model.NewSubscriptionEntity;
3337
import io.gravitee.rest.api.model.PlanEntity;
3438
import io.gravitee.rest.api.model.SubscriptionEntity;
39+
import io.gravitee.rest.api.model.SubscriptionStatus;
3540
import io.gravitee.rest.api.model.application.ApplicationListItem;
3641
import io.gravitee.rest.api.model.pagedresult.Metadata;
3742
import io.gravitee.rest.api.model.permissions.RolePermission;
3843
import io.gravitee.rest.api.model.permissions.RolePermissionAction;
39-
import io.gravitee.rest.api.portal.rest.mapper.SubscriptionMapper;
4044
import io.gravitee.rest.api.portal.rest.model.ApiKeyModeEnum;
4145
import io.gravitee.rest.api.portal.rest.model.Key;
4246
import io.gravitee.rest.api.portal.rest.model.Links;
@@ -79,17 +83,17 @@ public void init() {
7983

8084
SubscriptionEntity subscriptionEntity1 = new SubscriptionEntity();
8185
subscriptionEntity1.setId(SUBSCRIPTION);
86+
subscriptionEntity1.setStatus(SubscriptionStatus.ACCEPTED);
8287
SubscriptionEntity subscriptionEntity2 = new SubscriptionEntity();
8388
subscriptionEntity2.setId(ANOTHER_SUBSCRIPTION);
89+
subscriptionEntity2.setStatus(SubscriptionStatus.ACCEPTED);
8490
final Page<SubscriptionEntity> subscriptionPage = new Page<>(asList(subscriptionEntity1, subscriptionEntity2), 0, 1, 2);
8591
doReturn(subscriptionPage.getContent()).when(subscriptionService).search(eq(GraviteeContext.getExecutionContext()), any());
8692
doReturn(subscriptionPage).when(subscriptionService).search(any(), any(), any());
8793

88-
doReturn(new Subscription().id(SUBSCRIPTION)).when(SubscriptionMapper.INSTANCE).map(subscriptionEntity1);
89-
doReturn(new Subscription().id(ANOTHER_SUBSCRIPTION)).when(SubscriptionMapper.INSTANCE).map(subscriptionEntity2);
90-
9194
SubscriptionEntity createdSubscription = new SubscriptionEntity();
9295
createdSubscription.setId(SUBSCRIPTION);
96+
createdSubscription.setStatus(SubscriptionStatus.ACCEPTED);
9397
doReturn(createdSubscription).when(subscriptionService).create(eq(GraviteeContext.getExecutionContext()), any());
9498

9599
SubscriptionEntity subscriptionEntity = new SubscriptionEntity();

0 commit comments

Comments
 (0)