Skip to content

Commit 9a0ef4f

Browse files
feat(keys in ui): add keys view in UI (#92)
1 parent 77f913f commit 9a0ef4f

File tree

15 files changed

+1514
-37
lines changed

15 files changed

+1514
-37
lines changed

src/main/java/io/github/project/openubl/ublhub/models/jpa/ComponentRepository.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,12 @@ public Uni<List<ComponentModel>> getComponents(NamespaceEntity namespace, String
160160
);
161161
}
162162

163-
public Uni<ComponentModel> getComponent(String id) {
164-
return ComponentEntity.<ComponentEntity>findById(id)
163+
public Uni<ComponentModel> getComponent(NamespaceEntity namespace, String id) {
164+
return ComponentEntity
165+
.<ComponentEntity>find("SELECT DISTINCT c FROM ComponentEntity c LEFT JOIN FETCH c.componentConfigs WHERE c.namespace.id = :namespaceId and c.id = :id",
166+
Parameters.with("namespaceId", namespace.id).and("id", id)
167+
)
168+
.singleResult()
165169
.map(entity -> entity != null ? entityToModel(entity) : null);
166170
}
167171

src/main/java/io/github/project/openubl/ublhub/models/utils/EntityToRepresentation.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,17 @@
1919
import io.github.project.openubl.ublhub.idm.*;
2020
import io.github.project.openubl.ublhub.keys.component.ComponentModel;
2121
import io.github.project.openubl.ublhub.keys.component.utils.ComponentUtil;
22+
import io.github.project.openubl.ublhub.keys.provider.ProviderConfigProperty;
2223
import io.github.project.openubl.ublhub.keys.utils.StripSecretsUtils;
2324
import io.github.project.openubl.ublhub.models.jpa.entities.CompanyEntity;
2425
import io.github.project.openubl.ublhub.models.jpa.entities.NamespaceEntity;
2526
import io.github.project.openubl.ublhub.models.jpa.entities.SunatEntity;
2627
import io.github.project.openubl.ublhub.models.jpa.entities.UBLDocumentEntity;
2728
import org.keycloak.common.util.MultivaluedHashMap;
2829
import org.keycloak.representations.idm.ComponentRepresentation;
30+
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
2931

32+
import java.util.LinkedList;
3033
import java.util.List;
3134
import java.util.function.Function;
3235
import java.util.stream.Collectors;
@@ -146,27 +149,27 @@ public static ComponentRepresentation toRepresentationWithoutConfig(ComponentMod
146149
return rep;
147150
}
148151

149-
// public static List<ConfigPropertyRepresentation> toRepresentation(List<ProviderConfigProperty> configProperties) {
150-
// List<ConfigPropertyRepresentation> propertiesRep = new LinkedList<>();
151-
// for (ProviderConfigProperty prop : configProperties) {
152-
// ConfigPropertyRepresentation propRep = toRepresentation(prop);
153-
// propertiesRep.add(propRep);
154-
// }
155-
// return propertiesRep;
156-
// }
157-
//
158-
// public static ConfigPropertyRepresentation toRepresentation(ProviderConfigProperty prop) {
159-
// ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
160-
// propRep.setName(prop.getName());
161-
// propRep.setLabel(prop.getLabel());
162-
// propRep.setType(prop.getType());
163-
// propRep.setDefaultValue(prop.getDefaultValue());
164-
// propRep.setOptions(prop.getOptions());
165-
// propRep.setHelpText(prop.getHelpText());
166-
// propRep.setSecret(prop.isSecret());
167-
// return propRep;
168-
// }
169-
//
152+
public static List<ConfigPropertyRepresentation> toRepresentation(List<ProviderConfigProperty> configProperties) {
153+
List<ConfigPropertyRepresentation> propertiesRep = new LinkedList<>();
154+
for (ProviderConfigProperty prop : configProperties) {
155+
ConfigPropertyRepresentation propRep = toRepresentation(prop);
156+
propertiesRep.add(propRep);
157+
}
158+
return propertiesRep;
159+
}
160+
161+
public static ConfigPropertyRepresentation toRepresentation(ProviderConfigProperty prop) {
162+
ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
163+
propRep.setName(prop.getName());
164+
propRep.setLabel(prop.getLabel());
165+
propRep.setType(prop.getType());
166+
propRep.setDefaultValue(prop.getDefaultValue());
167+
propRep.setOptions(prop.getOptions());
168+
propRep.setHelpText(prop.getHelpText());
169+
propRep.setSecret(prop.isSecret());
170+
return propRep;
171+
}
172+
170173
public static <T, R> PageRepresentation<R> toRepresentation(List<T> pageElements, Long totalElements, Function<T, R> mapper) {
171174
PageRepresentation<R> rep = new PageRepresentation<>();
172175

@@ -185,7 +188,4 @@ public static <T, R> PageRepresentation<R> toRepresentation(List<T> pageElements
185188
return rep;
186189
}
187190

188-
// private static URIBuilder getURIBuilder(UriInfo uriInfo) throws URISyntaxException {
189-
// return new URIBuilder(uriInfo.getPath());
190-
// }
191191
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package io.github.project.openubl.ublhub.models.utils;
2+
3+
import io.github.project.openubl.ublhub.keys.component.ComponentModel;
4+
import io.github.project.openubl.ublhub.keys.component.utils.ComponentUtil;
5+
import io.github.project.openubl.ublhub.keys.provider.ProviderConfigProperty;
6+
import org.keycloak.common.util.MultivaluedHashMap;
7+
import org.keycloak.representations.idm.ComponentRepresentation;
8+
9+
import java.util.*;
10+
11+
public class RepresentationToModel {
12+
13+
public static ComponentModel toModel(ComponentRepresentation rep) {
14+
ComponentModel model = new ComponentModel();
15+
model.setId(rep.getId());
16+
model.setParentId(rep.getParentId());
17+
model.setProviderType(rep.getProviderType());
18+
model.setProviderId(rep.getProviderId());
19+
model.setConfig(new MultivaluedHashMap<>());
20+
model.setName(rep.getName());
21+
model.setSubType(rep.getSubType());
22+
23+
if (rep.getConfig() != null) {
24+
Set<String> keys = new HashSet<>(rep.getConfig().keySet());
25+
for (String k : keys) {
26+
List<String> values = rep.getConfig().get(k);
27+
if (values != null) {
28+
ListIterator<String> itr = values.listIterator();
29+
while (itr.hasNext()) {
30+
String v = itr.next();
31+
if (v == null || v.trim().isEmpty()) {
32+
itr.remove();
33+
}
34+
}
35+
36+
if (!values.isEmpty()) {
37+
model.getConfig().put(k, values);
38+
}
39+
}
40+
}
41+
}
42+
43+
return model;
44+
}
45+
46+
public static void updateComponent(ComponentRepresentation rep, ComponentModel component, boolean internal, ComponentUtil componentUtil) {
47+
if (rep.getName() != null) {
48+
component.setName(rep.getName());
49+
}
50+
51+
if (rep.getParentId() != null) {
52+
component.setParentId(rep.getParentId());
53+
}
54+
55+
if (rep.getProviderType() != null) {
56+
component.setProviderType(rep.getProviderType());
57+
}
58+
59+
if (rep.getProviderId() != null) {
60+
component.setProviderId(rep.getProviderId());
61+
}
62+
63+
if (rep.getSubType() != null) {
64+
component.setSubType(rep.getSubType());
65+
}
66+
67+
Map<String, ProviderConfigProperty> providerConfiguration = null;
68+
if (!internal) {
69+
providerConfiguration = componentUtil.getComponentConfigProperties(component);
70+
}
71+
72+
if (rep.getConfig() != null) {
73+
Set<String> keys = new HashSet<>(rep.getConfig().keySet());
74+
for (String k : keys) {
75+
if (!internal && !providerConfiguration.containsKey(k)) {
76+
break;
77+
}
78+
79+
List<String> values = rep.getConfig().get(k);
80+
if (values == null || values.isEmpty() || values.get(0) == null || values.get(0).trim().isEmpty()) {
81+
component.getConfig().remove(k);
82+
} else {
83+
ListIterator<String> itr = values.listIterator();
84+
while (itr.hasNext()) {
85+
String v = itr.next();
86+
if (v == null || v.trim().isEmpty() || v.equals(ComponentRepresentation.SECRET_VALUE)) {
87+
itr.remove();
88+
}
89+
}
90+
91+
if (!values.isEmpty()) {
92+
component.getConfig().put(k, values);
93+
}
94+
}
95+
}
96+
}
97+
}
98+
99+
100+
}

src/main/java/io/github/project/openubl/ublhub/resources/NamespaceResource.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.github.project.openubl.ublhub.idm.PageRepresentation;
2222
import io.github.project.openubl.ublhub.keys.DefaultKeyProviders;
2323
import io.github.project.openubl.ublhub.keys.KeyManager;
24+
import io.github.project.openubl.ublhub.keys.component.ComponentModel;
2425
import io.github.project.openubl.ublhub.keys.component.utils.ComponentUtil;
2526
import io.github.project.openubl.ublhub.models.PageBean;
2627
import io.github.project.openubl.ublhub.models.SortBean;
@@ -30,6 +31,7 @@
3031
import io.github.project.openubl.ublhub.models.jpa.entities.SunatEntity;
3132
import io.github.project.openubl.ublhub.models.utils.EntityToRepresentation;
3233
import io.github.project.openubl.ublhub.models.utils.RepresentationToEntity;
34+
import io.github.project.openubl.ublhub.models.utils.RepresentationToModel;
3335
import io.github.project.openubl.ublhub.resources.utils.ResourceUtils;
3436
import io.quarkus.hibernate.reactive.panache.Panache;
3537
import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
@@ -38,6 +40,7 @@
3840
import org.jboss.logging.Logger;
3941
import org.keycloak.common.util.PemUtils;
4042
import org.keycloak.crypto.KeyWrapper;
43+
import org.keycloak.representations.idm.ComponentRepresentation;
4144
import org.keycloak.representations.idm.KeysMetadataRepresentation;
4245

4346
import javax.enterprise.context.ApplicationScoped;
@@ -233,6 +236,75 @@ public Uni<Response> getComponents(
233236
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND)::build);
234237
}
235238

239+
@POST
240+
@Path("/{namespaceId}/components")
241+
public Uni<Response> createComponent(
242+
@PathParam("namespaceId") @NotNull String namespaceId,
243+
ComponentRepresentation rep
244+
) {
245+
return Panache
246+
.withTransaction(() -> namespaceRepository.findById(namespaceId)
247+
.onItem().ifNotNull().transformToUni(namespace -> {
248+
ComponentModel model = RepresentationToModel.toModel(rep);
249+
model.setId(null);
250+
return componentRepository.addComponentModel(namespace, model);
251+
})
252+
.map(entity -> Response.status(Response.Status.CREATED).build())
253+
)
254+
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND)::build);
255+
}
256+
257+
@GET
258+
@Path("/{namespaceId}/components/{componentId}")
259+
public Uni<Response> getComponent(
260+
@PathParam("namespaceId") @NotNull String namespaceId,
261+
@PathParam("componentId") String componentId
262+
) {
263+
return Panache
264+
.withTransaction(() -> namespaceRepository.findById(namespaceId)
265+
.onItem().ifNotNull().transformToUni(namespace -> componentRepository.getComponent(namespace, componentId))
266+
)
267+
.onItem().ifNotNull().transform(componentModel -> Response.ok().entity(EntityToRepresentation.toRepresentation(componentModel, false, componentUtil)).build())
268+
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND)::build);
269+
}
270+
271+
@PUT
272+
@Path("/{namespaceId}/components/{componentId}")
273+
public Uni<Response> updateComponent(
274+
@PathParam("namespaceId") @NotNull String namespaceId,
275+
@PathParam("componentId") String componentId,
276+
ComponentRepresentation rep
277+
) {
278+
return Panache
279+
.withTransaction(() -> namespaceRepository.findById(namespaceId)
280+
.onItem().ifNotNull().transformToUni(namespace -> componentRepository.getComponent(namespace, componentId)
281+
.chain(componentModel -> {
282+
RepresentationToModel.updateComponent(rep, componentModel, false, componentUtil);
283+
return componentRepository
284+
.updateComponent(namespace, componentModel)
285+
.chain(() -> componentRepository.getComponent(namespace, componentId));
286+
})
287+
)
288+
.map(componentModel -> Response.ok().entity(EntityToRepresentation.toRepresentation(componentModel, false, componentUtil)).build())
289+
)
290+
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND)::build);
291+
}
292+
293+
@DELETE
294+
@Path("/{namespaceId}/components/{componentId}")
295+
public Uni<Response> removeComponent(
296+
@PathParam("namespaceId") @NotNull String namespaceId,
297+
@PathParam("componentId") String componentId
298+
) {
299+
return Panache
300+
.withTransaction(() -> namespaceRepository.findById(namespaceId)
301+
.onItem().ifNotNull().transformToUni(namespace -> componentRepository.getComponent(namespace, componentId)
302+
.chain(componentModel -> componentRepository.removeComponent(componentModel))
303+
)
304+
.map((result) -> Response.ok().build())
305+
)
306+
.onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND)::build);
307+
}
236308
}
237309

238310

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package io.github.project.openubl.ublhub.resources;
2+
3+
/*
4+
* Copyright 2019 Project OpenUBL, Inc. and/or its affiliates
5+
* and other contributors as indicated by the @author tags.
6+
*
7+
* Licensed under the Eclipse Public License - v 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* https://www.eclipse.org/legal/epl-2.0/
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
import io.github.project.openubl.ublhub.idm.ServerInfoRepresentation;
21+
import io.github.project.openubl.ublhub.keys.KeyProvider;
22+
import io.github.project.openubl.ublhub.keys.KeyProviderFactory;
23+
import io.github.project.openubl.ublhub.keys.component.ComponentFactory;
24+
import io.github.project.openubl.ublhub.keys.provider.ProviderConfigProperty;
25+
import io.github.project.openubl.ublhub.models.utils.EntityToRepresentation;
26+
import org.keycloak.representations.idm.ComponentTypeRepresentation;
27+
28+
import javax.enterprise.context.ApplicationScoped;
29+
import javax.enterprise.inject.Any;
30+
import javax.enterprise.inject.Instance;
31+
import javax.inject.Inject;
32+
import javax.transaction.Transactional;
33+
import javax.ws.rs.Consumes;
34+
import javax.ws.rs.GET;
35+
import javax.ws.rs.Path;
36+
import javax.ws.rs.Produces;
37+
import javax.ws.rs.core.MediaType;
38+
import java.util.ArrayList;
39+
import java.util.Collections;
40+
import java.util.HashMap;
41+
import java.util.List;
42+
43+
@Path("/server-info")
44+
@Produces("application/json")
45+
@Consumes("application/json")
46+
@Transactional
47+
@ApplicationScoped
48+
public class ServerInfoResource {
49+
50+
@Inject
51+
@Any
52+
Instance<KeyProviderFactory> componentFactories;
53+
54+
@GET
55+
@Produces(MediaType.APPLICATION_JSON)
56+
public ServerInfoRepresentation getInfo() {
57+
ServerInfoRepresentation info = new ServerInfoRepresentation();
58+
setProviders(info);
59+
return info;
60+
}
61+
62+
private void setProviders(ServerInfoRepresentation info) {
63+
info.setComponentTypes(new HashMap<>());
64+
65+
List<ComponentTypeRepresentation> types = new ArrayList<>();
66+
67+
for (ComponentFactory componentFactory : componentFactories) {
68+
ComponentTypeRepresentation rep = new ComponentTypeRepresentation();
69+
rep.setId(componentFactory.getId());
70+
rep.setHelpText(componentFactory.getHelpText());
71+
List<ProviderConfigProperty> configProperties = componentFactory.getConfigProperties();
72+
if (configProperties == null) {
73+
configProperties = Collections.emptyList();
74+
}
75+
rep.setProperties(EntityToRepresentation.toRepresentation(configProperties));
76+
77+
types.add(rep);
78+
}
79+
80+
info.getComponentTypes().put(KeyProvider.class.getName(), types);
81+
info.getComponentTypes().put("keyProviders", types);
82+
}
83+
84+
}
85+

0 commit comments

Comments
 (0)