diff --git a/docs/modules/onecx-workspace-svc/pages/onecx-workspace-svc-extensions.adoc b/docs/modules/onecx-workspace-svc/pages/onecx-workspace-svc-extensions.adoc index 388a544..c4ae3e9 100644 --- a/docs/modules/onecx-workspace-svc/pages/onecx-workspace-svc-extensions.adoc +++ b/docs/modules/onecx-workspace-svc/pages/onecx-workspace-svc-extensions.adoc @@ -47,8 +47,8 @@ h| Version | onecx-tenant | https://onecx.github.io/docs/onecx-quarkus/current/onecx-quarkus/onecx-tenant.html[Link] -| https://github.com/onecx/onecx-quarkus/blob/0.33.0/docs/modules/onecx-quarkus/pages/includes/onecx-tenant.adoc[Link] -| 0.33.0 +| https://github.com/onecx/onecx-quarkus/blob/0.34.0/docs/modules/onecx-quarkus/pages/includes/onecx-tenant.adoc[Link] +| 0.34.0 | tkit-quarkus-jpa-tenant @@ -144,7 +144,7 @@ h| Version | https://onecx.github.io/docs/onecx-quarkus/current/onecx-quarkus/onecx-core.html[Link] | -| 0.33.0 +| 0.34.0 | quarkus-container-image-docker @@ -157,7 +157,7 @@ h| Version | | -| 0.33.0 +| 0.34.0 |=== \ No newline at end of file diff --git a/src/main/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestController.java b/src/main/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestController.java index b5f8612..a4d45e6 100644 --- a/src/main/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestController.java +++ b/src/main/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestController.java @@ -1,8 +1,11 @@ package org.tkit.onecx.workspace.rs.internal.controllers; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toSet; import static org.jboss.resteasy.reactive.RestResponse.StatusCode.NOT_FOUND; import java.util.*; +import java.util.stream.Collectors; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @@ -15,8 +18,10 @@ import org.jboss.resteasy.reactive.RestResponse; import org.jboss.resteasy.reactive.server.ServerExceptionMapper; +import org.tkit.onecx.workspace.domain.daos.AssignmentDAO; import org.tkit.onecx.workspace.domain.daos.MenuItemDAO; import org.tkit.onecx.workspace.domain.daos.WorkspaceDAO; +import org.tkit.onecx.workspace.domain.models.AssignmentMenu; import org.tkit.onecx.workspace.domain.models.MenuItem; import org.tkit.onecx.workspace.domain.services.MenuService; import org.tkit.onecx.workspace.rs.internal.mappers.InternalExceptionMapper; @@ -26,7 +31,9 @@ import gen.org.tkit.onecx.workspace.rs.internal.MenuInternalApi; import gen.org.tkit.onecx.workspace.rs.internal.model.*; +import lombok.extern.slf4j.Slf4j; +@Slf4j @LogService @ApplicationScoped @Transactional(Transactional.TxType.NOT_SUPPORTED) @@ -50,6 +57,9 @@ public class MenuInternalRestController implements MenuInternalApi { @Inject MenuService menuService; + @Inject + AssignmentDAO assignmentDAO; + @Override public Response createMenuItem(CreateMenuItemDTO menuItemDTO) { var workspace = workspaceDAO.findById(menuItemDTO.getWorkspaceId()); @@ -107,7 +117,20 @@ public Response getMenuItemById(String menuItemId) { public Response getMenuStructure(MenuStructureSearchCriteriaDTO menuStructureSearchCriteriaDTO) { var criteria = mapper.map(menuStructureSearchCriteriaDTO); var result = dao.loadAllMenuItemsByCriteria(criteria); - return Response.ok(mapper.mapTree(result)).build(); + var workspace = workspaceDAO.findById(criteria.getWorkspaceId()); + if (menuStructureSearchCriteriaDTO.getRoles().isEmpty()) { + return Response.ok(mapper.mapTree(result)).build(); + + } + + List assignmentRecords = assignmentDAO + .findAssignmentMenuForWorkspace(menuStructureSearchCriteriaDTO.getWorkspaceId()); + Map> mapping = assignmentRecords.stream() + .collect(Collectors.groupingBy(AssignmentMenu::menuItemId, mapping(AssignmentMenu::roleName, toSet()))); + return Response + .ok(mapper.mapTreeByRoles(workspace, result, mapping, new HashSet<>(menuStructureSearchCriteriaDTO.getRoles()))) + .build(); + } @Override diff --git a/src/main/java/org/tkit/onecx/workspace/rs/internal/mappers/MenuItemMapper.java b/src/main/java/org/tkit/onecx/workspace/rs/internal/mappers/MenuItemMapper.java index c195201..2416265 100644 --- a/src/main/java/org/tkit/onecx/workspace/rs/internal/mappers/MenuItemMapper.java +++ b/src/main/java/org/tkit/onecx/workspace/rs/internal/mappers/MenuItemMapper.java @@ -1,10 +1,9 @@ package org.tkit.onecx.workspace.rs.internal.mappers; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; +import org.apache.commons.text.StringSubstitutor; import org.mapstruct.*; import org.tkit.onecx.workspace.domain.criteria.MenuItemLoadCriteria; import org.tkit.onecx.workspace.domain.criteria.MenuItemSearchCriteria; @@ -142,4 +141,67 @@ default void updateMenu(MenuItem menuItem, int position, Workspace workspace, menuItem.setPosition(position); menuItem.setParent(parent); } + + default MenuItemStructureDTO mapTreeByRoles(Workspace workspace, Collection menuItems, + Map> mapping, + HashSet roles) { + MenuItemStructureDTO dto = new MenuItemStructureDTO(); + + if (menuItems.isEmpty()) { + return dto; + } + Set items; + + items = filterMenu(new HashSet<>(menuItems), mapping, roles, workspace.getBaseUrl()); + if (items.isEmpty()) { + return dto; + } + + return dto.menuItems(items.stream().map(this::mapTreeItem).toList()); + } + + default Set filterMenu(Set items, Map> mapping, Set roles, + String workspaceUrl) { + Set tmp = new HashSet<>(items); + final var sub = new StringSubstitutor(System.getenv()); + tmp.forEach(rootItem -> { + var mr = mapping.get(rootItem.getId()); + if (mr == null || mr.stream().noneMatch(roles::contains)) { + items.remove(rootItem); + } else { + if (rootItem.getChildren() != null && !rootItem.getChildren().isEmpty()) { + filterChildren(rootItem, mapping, roles, workspaceUrl, sub); + } else { + rootItem.setUrl(updateInternalUrl(workspaceUrl, rootItem.getUrl(), rootItem.isExternal(), sub)); + } + } + }); + + return items; + } + + default void filterChildren(MenuItem menuItem, Map> mapping, Set roles, + String workspaceUrl, StringSubstitutor sub) { + Set items = new HashSet<>(menuItem.getChildren()); + items.forEach(child -> { + var mr = mapping.get(child.getId()); + if (mr == null || mr.stream().noneMatch(roles::contains)) { + menuItem.getChildren().remove(child); + } else { + if (child.getChildren() != null && !child.getChildren().isEmpty()) { + filterChildren(child, mapping, roles, workspaceUrl, sub); + } else { + child.setUrl(updateInternalUrl(workspaceUrl, child.getUrl(), child.isExternal(), sub)); + } + } + }); + } + + default String updateInternalUrl(String workspaceUrl, String menuItemUrl, Boolean isExternal, StringSubstitutor sub) { + if (Boolean.TRUE.equals(isExternal)) { + return sub.replace(menuItemUrl); + } else { + return sub.replace(workspaceUrl + menuItemUrl); + } + } } diff --git a/src/main/openapi/onecx-workspace-internal-openapi.yaml b/src/main/openapi/onecx-workspace-internal-openapi.yaml index 39974b8..60277ec 100644 --- a/src/main/openapi/onecx-workspace-internal-openapi.yaml +++ b/src/main/openapi/onecx-workspace-internal-openapi.yaml @@ -840,6 +840,10 @@ components: required: - workspaceId properties: + roles: + type: array + items: + type: string workspaceId: type: string MenuItemSearchCriteria: diff --git a/src/test/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestControllerTest.java b/src/test/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestControllerTest.java index 8e8bdb2..7ba470f 100644 --- a/src/test/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestControllerTest.java +++ b/src/test/java/org/tkit/onecx/workspace/rs/internal/controllers/MenuInternalRestControllerTest.java @@ -8,6 +8,7 @@ import static org.tkit.quarkus.security.test.SecurityTestUtils.getKeycloakClientToken; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.stream.Stream; @@ -290,6 +291,25 @@ void getMenuStructureForWorkspaceIdTest() { assertThat(countMenuItems(data.getMenuItems())).isEqualTo(13); } + @Test + void getMenuStructureForWorkspaceIdAndRolesTest() { + var criteria = new MenuStructureSearchCriteriaDTO().workspaceId("11-111").roles(List.of("n3", "n4")); + + var data = given() + .auth().oauth2(getKeycloakClientToken("testClient")) + .when() + .contentType(APPLICATION_JSON) + .body(criteria) + .post("/tree") + .then() + .statusCode(OK.getStatusCode()) + .extract().body().as(MenuItemStructureDTO.class); + + assertThat(data).isNotNull(); + assertThat(data.getMenuItems()).hasSize(3); + assertThat(countMenuItems(data.getMenuItems())).isEqualTo(4); + } + private int countMenuItems(Collection menuItemDTOS) { int count = 0; for (WorkspaceMenuItemDTO item : menuItemDTOS) {