From 38ac1e91bc278841c0562e182fc1f185285cb1e9 Mon Sep 17 00:00:00 2001 From: JordenReuter <149687553+JordenReuter@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:38:32 +0200 Subject: [PATCH] feat: added exim for ui (#94) --- .../controllers/PermissionExportImportV1.java | 16 +++++ .../rs/exim/v1/mappers/EximMapperV1.java | 30 ++++++++++ .../onecx-permission-exim-v1-openapi.yaml | 60 +++++++++++++++++++ .../PermissionExportImportV1Test.java | 35 +++++++++-- src/test/resources/data/test-exim-v1.xml | 6 ++ 5 files changed, 142 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1.java b/src/main/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1.java index cf34fe0..39a8c33 100644 --- a/src/main/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1.java +++ b/src/main/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1.java @@ -10,6 +10,7 @@ import org.jboss.resteasy.reactive.RestResponse; import org.jboss.resteasy.reactive.server.ServerExceptionMapper; +import org.tkit.onecx.permission.domain.daos.AssignmentDAO; import org.tkit.onecx.permission.domain.daos.PermissionDAO; import org.tkit.onecx.permission.domain.daos.RoleDAO; import org.tkit.onecx.permission.domain.models.Role; @@ -22,6 +23,7 @@ import gen.org.tkit.onecx.permission.rs.exim.v1.model.AssignmentSnapshotDTOV1; import gen.org.tkit.onecx.permission.rs.exim.v1.model.EximProblemDetailInvalidParamDTOV1; import gen.org.tkit.onecx.permission.rs.exim.v1.model.EximProblemDetailResponseDTOV1; +import gen.org.tkit.onecx.permission.rs.exim.v1.model.ExportAssignmentsRequestDTOV1; @LogService @ApplicationScoped @@ -42,6 +44,20 @@ public class PermissionExportImportV1 implements PermissionExportImportApi { @Inject AssignmentService service; + @Inject + AssignmentDAO assignmentDAO; + + @Override + public Response exportAssignments(ExportAssignmentsRequestDTOV1 exportAssignmentsRequestDTOV1) { + var permissionActions = assignmentDAO.findPermissionActionForProducts(exportAssignmentsRequestDTOV1.getProductNames()); + return Response.ok(mapper.createSnapshot(permissionActions)).build(); + } + + @Override + public Response importAssignments(AssignmentSnapshotDTOV1 assignmentSnapshotDTOV1) { + return operatorImportAssignments(assignmentSnapshotDTOV1); + } + @Override public Response operatorImportAssignments(AssignmentSnapshotDTOV1 assignmentSnapshotDTO) { diff --git a/src/main/java/org/tkit/onecx/permission/rs/exim/v1/mappers/EximMapperV1.java b/src/main/java/org/tkit/onecx/permission/rs/exim/v1/mappers/EximMapperV1.java index 0ccf06a..e9c0055 100644 --- a/src/main/java/org/tkit/onecx/permission/rs/exim/v1/mappers/EximMapperV1.java +++ b/src/main/java/org/tkit/onecx/permission/rs/exim/v1/mappers/EximMapperV1.java @@ -1,11 +1,13 @@ package org.tkit.onecx.permission.rs.exim.v1.mappers; +import java.time.OffsetDateTime; import java.util.*; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.tkit.onecx.permission.domain.models.Assignment; import org.tkit.onecx.permission.domain.models.Permission; +import org.tkit.onecx.permission.domain.models.PermissionAction; import org.tkit.onecx.permission.domain.models.Role; import gen.org.tkit.onecx.permission.rs.exim.v1.model.AssignmentSnapshotDTOV1; @@ -125,4 +127,32 @@ static String permId(String productName, String appId, String resource, String a record RequestData(Map> product, Set roles) { } + + default AssignmentSnapshotDTOV1 createSnapshot(List items) { + AssignmentSnapshotDTOV1 assignmentSnapshotDTOV1 = new AssignmentSnapshotDTOV1(); + assignmentSnapshotDTOV1.setId(UUID.randomUUID().toString()); + assignmentSnapshotDTOV1.setCreated(OffsetDateTime.now()); + assignmentSnapshotDTOV1.setAssignments(createSnapshotAssignments(items)); + return assignmentSnapshotDTOV1; + } + + default Map>>>> createSnapshotAssignments( + List items) { + + if (items == null) { + return Map.of(); + } + Map>>>> result = new HashMap<>(); + + for (PermissionAction permissionAction : items) { + result + .computeIfAbsent(permissionAction.productName(), k -> new HashMap<>()) + .computeIfAbsent(permissionAction.applicationId(), k -> new HashMap<>()) + .computeIfAbsent(permissionAction.roleName(), k -> new HashMap<>()) + .computeIfAbsent(permissionAction.resource(), k -> new ArrayList<>()) + .add(permissionAction.action()); + } + + return result; + } } diff --git a/src/main/openapi/onecx-permission-exim-v1-openapi.yaml b/src/main/openapi/onecx-permission-exim-v1-openapi.yaml index 7e1b4b3..c2aaef3 100644 --- a/src/main/openapi/onecx-permission-exim-v1-openapi.yaml +++ b/src/main/openapi/onecx-permission-exim-v1-openapi.yaml @@ -37,6 +37,58 @@ paths: application/json: schema: $ref: '#/components/schemas/EximProblemDetailResponse' + /exim/v1/assignments/import: + post: + security: + - oauth2: [ ocx-pm:write ] + tags: + - permissionExportImport + description: Operator import assignments + operationId: importAssignments + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AssignmentSnapshot' + responses: + "200": + description: Import successful + "409": + description: The request could not be fully completed due to a conflict with the current state of the roles and permissions + content: + application/json: + schema: + $ref: '#/components/schemas/EximProblemDetailResponse' + "400": + description: Bad request + content: + application/json: + schema: + $ref: '#/components/schemas/EximProblemDetailResponse' + /exim/v1/assignments/export: + post: + security: + - oauth2: [ ocx-pm:read ] + tags: + - permissionExportImport + description: Operator import assignments + operationId: exportAssignments + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExportAssignmentsRequest' + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/AssignmentSnapshot' + "404": + description: No helps found components: securitySchemes: oauth2: @@ -83,6 +135,14 @@ components: type: array items: type: string + ExportAssignmentsRequest: + type: object + properties: + productNames: + type: array + uniqueItems: true + items: + type: string EximProblemDetailResponse: type: object properties: diff --git a/src/test/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1Test.java b/src/test/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1Test.java index 6f1dcf2..57280f2 100644 --- a/src/test/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1Test.java +++ b/src/test/java/org/tkit/onecx/permission/rs/exim/v1/controllers/PermissionExportImportV1Test.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.junit.jupiter.api.Test; import org.tkit.onecx.permission.rs.exim.v1.mappers.EximExceptionMapperV1; @@ -18,6 +19,7 @@ import gen.org.tkit.onecx.permission.rs.exim.v1.model.AssignmentSnapshotDTOV1; import gen.org.tkit.onecx.permission.rs.exim.v1.model.EximProblemDetailResponseDTOV1; +import gen.org.tkit.onecx.permission.rs.exim.v1.model.ExportAssignmentsRequestDTOV1; import io.quarkus.test.common.http.TestHTTPEndpoint; import io.quarkus.test.junit.QuarkusTest; @@ -36,7 +38,7 @@ void operatorImportNullProductTest() { .auth().oauth2(getKeycloakClientToken("testClient")) .contentType(APPLICATION_JSON) .body(request) - .post() + .post("/operator") .then().log().all() .statusCode(OK.getStatusCode()); } @@ -52,7 +54,7 @@ void operatorImportNullAppTest() { .auth().oauth2(getKeycloakClientToken("testClient")) .contentType(APPLICATION_JSON) .body(request) - .post() + .post("/operator") .then().log().all() .statusCode(OK.getStatusCode()); } @@ -70,7 +72,7 @@ void operatorImportTest() { .auth().oauth2(getKeycloakClientToken("testClient")) .contentType(APPLICATION_JSON) .body(request) - .post() + .post("/operator") .then().log().all() .statusCode(OK.getStatusCode()); } @@ -86,7 +88,7 @@ void operatorImportMissingDataTest() { .auth().oauth2(getKeycloakClientToken("testClient")) .contentType(APPLICATION_JSON) .body(request) - .post() + .post("/operator") .then().log().all() .statusCode(CONFLICT.getStatusCode()) .extract() @@ -105,7 +107,7 @@ void operatorImportEmptyBodyTest() { var dto = given() .auth().oauth2(getKeycloakClientToken("testClient")) .contentType(APPLICATION_JSON) - .post() + .post("/operator") .then().log().all() .statusCode(BAD_REQUEST.getStatusCode()) .extract() @@ -117,4 +119,27 @@ void operatorImportEmptyBodyTest() { "operatorImportAssignments.assignmentSnapshotDTOV1: must not be null"); } + @Test + void exportImportTest() { + var exportRequest = new ExportAssignmentsRequestDTOV1().productNames(Set.of("test1")); + var dto = given() + .auth().oauth2(getKeycloakClientToken("testClient")) + .contentType(APPLICATION_JSON) + .body(exportRequest) + .post("/export") + .then().log().all() + .statusCode(OK.getStatusCode()) + .extract() + .body().as(AssignmentSnapshotDTOV1.class); + assertThat(dto).isNotNull(); + + //snapshot should be importable + given() + .auth().oauth2(getKeycloakClientToken("testClient")) + .contentType(APPLICATION_JSON) + .body(dto) + .post("/import") + .then().log().all() + .statusCode(OK.getStatusCode()); + } } diff --git a/src/test/resources/data/test-exim-v1.xml b/src/test/resources/data/test-exim-v1.xml index 35d0de3..401e77e 100644 --- a/src/test/resources/data/test-exim-v1.xml +++ b/src/test/resources/data/test-exim-v1.xml @@ -28,4 +28,10 @@ + + + + + + \ No newline at end of file