Skip to content

Commit

Permalink
feat: added delete application endpoint (#108)
Browse files Browse the repository at this point in the history
* feat: added delete application endpoint

* fix: sonar issue
  • Loading branch information
JordenReuter authored Nov 11, 2024
1 parent 1e73be2 commit 1e9e222
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ h| Version

| https://onecx.github.io/docs/onecx-quarkus/current/onecx-quarkus/onecx-core.html[Link]
|
| 0.33.0
| 0.34.0

| 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-data-import

Expand Down Expand Up @@ -157,7 +157,7 @@ h| Version
|
|
| 0.33.0
| 0.34.0
| quarkus-smallrye-context-propagation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ public PageResult<Application> findByCriteria(ApplicationSearchCriteria criteria
}
}

public Application loadByName(String appName) {
try {
var cb = this.getEntityManager().getCriteriaBuilder();
var cq = cb.createQuery(Application.class);
var root = cq.from(Application.class);
cq.where(
cb.equal(root.get(Application_.NAME), appName));
return this.getEntityManager().createQuery(cq).getSingleResult();
} catch (NoResultException ne) {
return null;
} catch (Exception ex) {
throw new DAOException(ErrorKeys.ERROR_LOAD_BY_APP_NAME, ex);
}
}

public Application loadByAppId(String productName, String appId) {
try {
var cb = this.getEntityManager().getCriteriaBuilder();
Expand Down Expand Up @@ -78,6 +93,7 @@ public enum ErrorKeys {
ERROR_FIND_APPLICATIONS_BY_PRODUCT_NAMES,

ERROR_FIND_APPLICATIONS_BY_CRITERIA,
ERROR_LOAD_BY_APP_ID;
ERROR_LOAD_BY_APP_ID,
ERROR_LOAD_BY_APP_NAME;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ public void deleteByProducts(String roleId, List<String> productNames) {
}
}

@Transactional
public void deleteByPermissionIds(List<String> ids) {
try {
var dq = this.deleteQuery();
var root = dq.from(Assignment.class);
dq.where(root.get(Assignment_.PERMISSION).get(TraceableEntity_.ID).in(ids));
this.getEntityManager().createQuery(dq).executeUpdate();
} catch (Exception ex) {
throw new DAOException(ErrorKeys.ERROR_DELETE_BY_PERMISSION_IDS, ex);
}
}

public List<PermissionAction> findPermissionActionForProducts(Set<String> productNames) {
try {
var cb = this.getEntityManager().getCriteriaBuilder();
Expand Down Expand Up @@ -215,6 +227,7 @@ public enum ErrorKeys {
ERROR_LOAD_ASSIGNMENTS,
FIND_ENTITY_BY_ID_FAILED,
ERROR_FIND_ASSIGNMENT_BY_CRITERIA,
ERROR_SELECT_MANDATORY_BY_ROLE_ID;
ERROR_SELECT_MANDATORY_BY_ROLE_ID,
ERROR_DELETE_BY_PERMISSION_IDS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ public List<Permission> findByProductNames(Collection<String> productNames) {
}
}

public List<Permission> findByAppId(String appId) {
try {
var cb = this.getEntityManager().getCriteriaBuilder();
var cq = cb.createQuery(Permission.class);
var root = cq.from(Permission.class);
cq.where(cb.equal(root.get(Permission_.APP_ID), appId));
return this.getEntityManager().createQuery(cq).getResultList();
} catch (Exception ex) {
throw new DAOException(ErrorKeys.ERROR_FIND_BY_APP_ID, ex);
}
}

public List<Permission> findAllExcludingGivenIds(Collection<String> permissionGuids) {
try {
var cb = this.getEntityManager().getCriteriaBuilder();
Expand Down Expand Up @@ -149,6 +161,7 @@ public enum ErrorKeys {
ERROR_FIND_BY_PRODUCT_AND_APP_ID,
ERROR_FIND_PERMISSION_BY_CRITERIA,
ERROR_FIND_BY_PRODUCT_NAMES,
ERROR_FIND_NOT_BY_IDS;
ERROR_FIND_NOT_BY_IDS,
ERROR_FIND_BY_APP_ID;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.tkit.onecx.permission.domain.services;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;

import org.tkit.onecx.permission.domain.daos.ApplicationDAO;
import org.tkit.onecx.permission.domain.daos.AssignmentDAO;
import org.tkit.onecx.permission.domain.daos.PermissionDAO;
import org.tkit.quarkus.jpa.models.TraceableEntity;

@ApplicationScoped
public class ApplicationService {

@Inject
AssignmentDAO assignmentDAO;

@Inject
PermissionDAO permissionDAO;

@Inject
ApplicationDAO applicationDAO;

@Transactional
public void deleteApplicationAndRelatedPermissionsAndAssignmentsById(String id, String applicationId) {
applicationDAO.deleteQueryById(id);
var permissions = permissionDAO.findByAppId(applicationId);
var permissionsIds = permissions.stream().map(TraceableEntity::getId).toList();
assignmentDAO.deleteByPermissionIds(permissionsIds);
permissionDAO.delete(permissions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jboss.resteasy.reactive.RestResponse;
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
import org.tkit.onecx.permission.domain.daos.ApplicationDAO;
import org.tkit.onecx.permission.domain.services.ApplicationService;
import org.tkit.onecx.permission.rs.internal.mappers.ApplicationMapper;
import org.tkit.onecx.permission.rs.internal.mappers.ExceptionMapper;
import org.tkit.quarkus.log.cdi.LogService;
Expand All @@ -29,6 +30,20 @@ public class ApplicationRestController implements ApplicationInternalApi {
@Inject
ApplicationDAO dao;

@Inject
ApplicationService applicationService;

@Override
public Response deleteByApplicationName(String name) {
var application = dao.loadByName(name);
if (application == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
applicationService.deleteApplicationAndRelatedPermissionsAndAssignmentsById(application.getId(),
application.getAppId());
return Response.status(Response.Status.NO_CONTENT).build();
}

@Override
public Response searchApplications(ApplicationSearchCriteriaDTO applicationSearchCriteriaDTO) {
var criteria = mapper.map(applicationSearchCriteriaDTO);
Expand Down
23 changes: 23 additions & 0 deletions src/main/openapi/onecx-permission-internal-openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,29 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetailResponse'
/internal/applications/{name}:
delete:
security:
- oauth2: [ ocx-pm:all, ocx-pm:delete ]
tags:
- applicationInternal
description: delete application by name
operationId: deleteByApplicationName
parameters:
- name: name
in: path
required: true
schema:
type: string
responses:
204:
description: Application deleted
400:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ProblemDetailResponse'
components:
securitySchemes:
oauth2:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ void methodExceptionTests() {
ApplicationDAO.ErrorKeys.ERROR_LOAD_BY_APP_ID);
methodExceptionTests(() -> dao.findByCriteria(null),
ApplicationDAO.ErrorKeys.ERROR_FIND_APPLICATIONS_BY_CRITERIA);
methodExceptionTests(() -> dao.loadByName(null),
ApplicationDAO.ErrorKeys.ERROR_LOAD_BY_APP_NAME);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ void methodExceptionTests() {
AssignmentDAO.ErrorKeys.ERROR_FIND_USER_ASSIGNMENTS);
methodExceptionTests(() -> dao.loadAssignments(null),
AssignmentDAO.ErrorKeys.ERROR_LOAD_ASSIGNMENTS);

methodExceptionTests(() -> dao.deleteByPermissionIds(null),
AssignmentDAO.ErrorKeys.ERROR_DELETE_BY_PERMISSION_IDS);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ void methodExceptionTests() {
PermissionDAO.ErrorKeys.ERROR_FIND_NOT_BY_IDS);
methodExceptionTests(() -> dao.findUsersPermissions(null, 0, 0),
PermissionDAO.ErrorKeys.ERROR_FIND_PERMISSION_FOR_USER);
methodExceptionTests(() -> dao.findByAppId(null),
PermissionDAO.ErrorKeys.ERROR_FIND_BY_APP_ID);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import static io.restassured.RestAssured.given;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.assertj.core.api.Assertions.assertThat;
import static org.jboss.resteasy.reactive.RestResponse.Status.BAD_REQUEST;
import static org.jboss.resteasy.reactive.RestResponse.Status.OK;
import static org.jboss.resteasy.reactive.RestResponse.Status.*;
import static org.tkit.quarkus.security.test.SecurityTestUtils.getKeycloakClientToken;

import org.junit.jupiter.api.Test;
Expand All @@ -31,7 +30,7 @@ void searchTest() {
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.body(criteria)
.post()
.post("/search")
.then()
.statusCode(OK.getStatusCode())
.contentType(APPLICATION_JSON)
Expand All @@ -48,7 +47,7 @@ void searchTest() {
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.body(criteria)
.post()
.post("/search")
.then()
.statusCode(OK.getStatusCode())
.contentType(APPLICATION_JSON)
Expand All @@ -70,7 +69,7 @@ void searchCriteriaTest() {
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.body(criteria)
.post()
.post("/search")
.then()
.statusCode(OK.getStatusCode())
.contentType(APPLICATION_JSON)
Expand All @@ -88,7 +87,7 @@ void searchNoBodyTest() {
var exception = given()
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.post()
.post("/search")
.then()
.statusCode(BAD_REQUEST.getStatusCode())
.contentType(APPLICATION_JSON)
Expand All @@ -99,4 +98,26 @@ void searchNoBodyTest() {
assertThat(exception.getErrorCode()).isEqualTo(ExceptionMapper.ErrorKeys.CONSTRAINT_VIOLATIONS.name());
assertThat(exception.getDetail()).isEqualTo("searchApplications.applicationSearchCriteriaDTO: must not be null");
}

@Test
void deleteApplicationByName() {
given()
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.pathParam("name", "app1")
.delete("/{name}")
.then()
.statusCode(NO_CONTENT.getStatusCode());
}

@Test
void deleteApplicationByNotExistingName() {
given()
.auth().oauth2(getKeycloakClientToken("testClient"))
.contentType(APPLICATION_JSON)
.pathParam("name", "notExisting")
.delete("/{name}")
.then()
.statusCode(NOT_FOUND.getStatusCode());
}
}

0 comments on commit 1e9e222

Please sign in to comment.