Skip to content

Commit

Permalink
[conluz-68] Implemented endponit to delete a plant
Browse files Browse the repository at this point in the history
  • Loading branch information
viktorKhan committed Apr 12, 2024
1 parent c2f9a54 commit 74c5038
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.lucoenergia.conluz.domain.production.plant.delete;

import org.lucoenergia.conluz.domain.shared.PlantId;

public interface DeletePlantRepository {

void delete(PlantId id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.lucoenergia.conluz.domain.production.plant.delete;

import org.lucoenergia.conluz.domain.shared.PlantId;
import org.springframework.stereotype.Service;

@Service
public class DeletePlantService {

private final DeletePlantRepository repository;

public DeletePlantService(DeletePlantRepository repository) {
this.repository = repository;
}

public void delete(PlantId id) {
repository.delete(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
import org.lucoenergia.conluz.infrastructure.admin.user.UserEntity;
import org.lucoenergia.conluz.infrastructure.admin.user.UserRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Transactional
@Repository
public class DeleteUserRepositoryImpl implements DeleteUserRepository {
public class DeleteUserRepositoryDatabase implements DeleteUserRepository {

private final UserRepository userRepository;

public DeleteUserRepositoryImpl(UserRepository userRepository) {
public DeleteUserRepositoryDatabase(UserRepository userRepository) {
this.userRepository = userRepository;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.lucoenergia.conluz.infrastructure.production.plant.delete;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.lucoenergia.conluz.domain.production.plant.delete.DeletePlantService;
import org.lucoenergia.conluz.domain.shared.PlantId;
import org.lucoenergia.conluz.infrastructure.shared.web.apidocs.ApiTag;
import org.lucoenergia.conluz.infrastructure.shared.web.apidocs.response.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.UUID;

@RestController
@RequestMapping("/api/v1")
public class DeletePlantController {

private final DeletePlantService service;

public DeletePlantController(DeletePlantService service) {
this.service = service;
}

@DeleteMapping("/plants/{id}")
@Operation(
summary = "Removes a plant by ID",
description = """
This endpoint enables the removal of a plant from the system by specifying the plant's unique identifier within the endpoint path.
To utilize this endpoint, clients send a DELETE request with the targeted plant's ID, requiring authentication for secure access.
Upon successful deletion, the server responds with an HTTP status code of 200, indicating that the plant has been successfully removed.
In cases where the deletion process encounters errors, the server returns an appropriate error status code, along with a descriptive error message to guide clients in diagnosing and addressing the issue.
""",
tags = ApiTag.PLANTS,
operationId = "deletePlant"
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "Plant deleted successfully"
)
})
@ForbiddenErrorResponse
@UnauthorizedErrorResponse
@BadRequestErrorResponse
@InternalServerErrorResponse
@NotFoundErrorResponse
public void deletePlant(@PathVariable("id") UUID plantId) {
service.delete(PlantId.of(plantId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.lucoenergia.conluz.infrastructure.production.plant.delete;

import org.lucoenergia.conluz.domain.production.plant.PlantNotFoundException;
import org.lucoenergia.conluz.domain.production.plant.delete.DeletePlantRepository;
import org.lucoenergia.conluz.domain.shared.PlantId;
import org.lucoenergia.conluz.infrastructure.production.plant.PlantEntity;
import org.lucoenergia.conluz.infrastructure.production.plant.PlantRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Transactional
@Repository
public class DeletePlantRepositoryDatabase implements DeletePlantRepository {

private final PlantRepository plantRepository;

public DeletePlantRepositoryDatabase(PlantRepository plantRepository) {
this.plantRepository = plantRepository;
}

@Override
public void delete(PlantId id) {
Optional<PlantEntity> entity = plantRepository.findById(id.getId());
if (entity.isEmpty()) {
throw new PlantNotFoundException(id);
}
plantRepository.delete(entity.get());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.lucoenergia.conluz.domain.admin.supply.SupplyNotFoundException;
import org.lucoenergia.conluz.domain.production.plant.PlantAlreadyExistsException;
import org.lucoenergia.conluz.domain.production.plant.PlantNotFoundException;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -32,4 +33,17 @@ public ResponseEntity<RestError> handleException(PlantAlreadyExistsException e)
);
return new ResponseEntity<>(new RestError(HttpStatus.BAD_REQUEST.value(), message), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(PlantNotFoundException.class)
public ResponseEntity<RestError> handleException(PlantNotFoundException e) {

String plantId = e.getId().toString();

String message = messageSource.getMessage(
"error.plant.not.found",
Collections.singletonList(plantId).toArray(),
LocaleContextHolder.getLocale()
);
return new ResponseEntity<>(new RestError(HttpStatus.BAD_REQUEST.value(), message), HttpStatus.BAD_REQUEST);
}
}
1 change: 1 addition & 0 deletions src/main/resources/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ error.admin.user.already.initialized=Admin user already initialized.
error.user.already.exists=User with ID ''{0}'' already exists.
# Plants
error.plant.already.exists=Plant with code ''{0}'' already exists.
error.plant.not.found=Plant with ID ''{0}'' has not been found. Verify the ID is correct.
1 change: 1 addition & 0 deletions src/main/resources/messages_es.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ error.admin.user.already.initialized=El usuario admin ya ha sido initializado.
error.user.already.exists=El usuario con ID ''{0}'' ya existe.
# Plants
error.plant.already.exists=La planta con código ''{0}'' ya existe.
error.plant.not.found=La planta con identificador ''{0}'' no ha sido encontrada. Revise que el identificador sea correcto.
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.lucoenergia.conluz.infrastructure.production.plant.delete;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.lucoenergia.conluz.domain.admin.user.User;
import org.lucoenergia.conluz.domain.admin.user.UserMother;
import org.lucoenergia.conluz.domain.admin.user.create.CreateUserRepository;
import org.lucoenergia.conluz.domain.production.plant.Plant;
import org.lucoenergia.conluz.domain.production.plant.PlantMother;
import org.lucoenergia.conluz.domain.production.plant.create.CreatePlantRepository;
import org.lucoenergia.conluz.domain.production.plant.get.GetPlantRepository;
import org.lucoenergia.conluz.domain.shared.PlantId;
import org.lucoenergia.conluz.domain.shared.UserId;
import org.lucoenergia.conluz.infrastructure.shared.BaseControllerTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Transactional
class DeletePlantControllerTest extends BaseControllerTest {

@Autowired
private CreateUserRepository createUserRepository;
@Autowired
private CreatePlantRepository createPlantRepository;
@Autowired
private GetPlantRepository getPlantRepository;

@Test
void testDelete() throws Exception {

// Create two users
User userOne = UserMother.randomUser();
createUserRepository.create(userOne);
User userTwo = UserMother.randomUser();
createUserRepository.create(userTwo);

// Create three supplies
Plant plantOne = PlantMother.random(userOne).withCode("TS-456789").build();
createPlantRepository.create(plantOne, UserId.of(userOne.getId()));
Plant plantTwo = PlantMother.random(userOne).withCode("TS-123456").build();
plantTwo = createPlantRepository.create(plantTwo, UserId.of(userOne.getId()));
Plant plantThree = PlantMother.random(userTwo).withCode("TS-789456").build();
createPlantRepository.create(plantThree, UserId.of(userTwo.getId()));

// Login as default admin
String authHeader = loginAsDefaultAdmin();

mockMvc.perform(delete(String.format("/api/v1/plants/%s", plantTwo.getId()))
.header(HttpHeaders.AUTHORIZATION, authHeader)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
Assertions.assertTrue(getPlantRepository.findById(PlantId.of(plantTwo.getId())).isEmpty());
}

@Test
void testWithUnknown() throws Exception {

String authHeader = loginAsDefaultAdmin();

final String plantId = UUID.randomUUID().toString();

mockMvc.perform(delete("/api/v1/plants/" + plantId)
.header(HttpHeaders.AUTHORIZATION, authHeader)
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.timestamp").isNotEmpty())
.andExpect(jsonPath("$.status").value(HttpStatus.BAD_REQUEST.value()))
.andExpect(jsonPath("$.message").isNotEmpty())
.andExpect(jsonPath("$.traceId").isNotEmpty());
}

@Test
void testWithoutIdInPath() throws Exception {
final String authHeader = loginAsDefaultAdmin();

mockMvc.perform(delete("/api/v1/plants")
.header(HttpHeaders.AUTHORIZATION, authHeader)
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.timestamp").isNotEmpty())
.andExpect(jsonPath("$.status").value(HttpStatus.BAD_REQUEST.value()))
.andExpect(jsonPath("$.message").isNotEmpty())
.andExpect(jsonPath("$.traceId").isNotEmpty());
}

@Test
void testWithoutToken() throws Exception {

mockMvc.perform(delete("/api/v1/plants")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isUnauthorized())
.andExpect(jsonPath("$.timestamp").isNotEmpty())
.andExpect(jsonPath("$.status").value(HttpStatus.UNAUTHORIZED.value()))
.andExpect(jsonPath("$.message").isNotEmpty())
.andExpect(jsonPath("$.traceId").isNotEmpty());
}
}

0 comments on commit 74c5038

Please sign in to comment.