Skip to content
Merged

Dev #23

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import smartpot.com.api.Commands.Model.DTO.CommandDTO;
import smartpot.com.api.Commands.Model.Entity.Command;
import smartpot.com.api.Commands.Service.SCommandI;
import smartpot.com.api.Crops.Model.DTO.CropDTO;
import smartpot.com.api.Responses.DeleteResponse;
Expand Down Expand Up @@ -104,22 +103,8 @@ public ResponseEntity<?> getUserById(@PathVariable String id) {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
public ResponseEntity<?> executeCommand(@PathVariable String id, @PathVariable String response) {
/*
Command command = serviceCommand.getCommandById(id);
if (command != null) {
command.setStatus("EXECUTED");
command.setDateExecuted(new Date());
command.setResponse("SUCCESSFUL");
Command updatedCommand = serviceCommand.updateCommand(id, command);
return ResponseEntity.ok(updatedCommand);
} else {
return ResponseEntity.notFound().build();
}

*/

try {
return new ResponseEntity<>(serviceCommand.excuteCommand(id, response), HttpStatus.OK);
return new ResponseEntity<>(serviceCommand.executeCommand(id, response), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(new ErrorResponse("Error al actualizar el comando con ID '" + id + "' [" + e.getMessage() + "]", HttpStatus.NOT_FOUND.value()), HttpStatus.NOT_FOUND);
}
Expand All @@ -146,8 +131,23 @@ public ResponseEntity<?> deleteCommand(@Parameter(description = "ID único del c
}

@PutMapping("/Update/{id}")
public Command updateCommand(@PathVariable String id, @RequestBody Command updatedCommad) throws Exception {
return serviceCommand.updateCommand(id, updatedCommad);
@Operation(summary = "Eliminar un comando",
description = "Elimina un comando existente utilizando su ID. "
+ "Si el comando no existe o hay un error en el proceso, se devolverá un error con el código HTTP 404.",
responses = {
@ApiResponse(description = "Comando eliminado",
responseCode = "204",
content = @Content(mediaType = "application/json")),
@ApiResponse(responseCode = "404",
description = "Comando no encontrado o error en la eliminación.",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
public ResponseEntity<?> updateCommand(@PathVariable String id, @RequestBody CommandDTO updatedCommand) {
try {
return new ResponseEntity<>(new DeleteResponse("Se ha eliminado un recurso [" + serviceCommand.updateCommand(id, updatedCommand) + "]"), HttpStatus.OK);
} catch (Exception e) {
return new ResponseEntity<>(new ErrorResponse("Error al actualizar el comando con ID '" + id + "' [" + e.getMessage() + "]", HttpStatus.NOT_FOUND.value()), HttpStatus.NOT_FOUND);
}
}

}
263 changes: 158 additions & 105 deletions src/main/java/smartpot/com/api/Commands/Service/SCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,60 @@
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import smartpot.com.api.Commands.Mapper.MCommand;
import smartpot.com.api.Commands.Model.DTO.CommandDTO;
import smartpot.com.api.Commands.Model.Entity.Command;
import smartpot.com.api.Commands.Repository.RCommand;
import smartpot.com.api.Crops.Service.SCropI;
import smartpot.com.api.Exception.ApiException;
import smartpot.com.api.Exception.ApiResponse;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import java.util.stream.Collectors;

/**
* Service implementation for managing commands.
*
* <p>
* This class provides the business logic for managing commands, including
* CRUD operations and execution logic. It interacts with the repository,
* a mapper, and additional services to fulfill its responsibilities.
* </p>
*
* <h3>Annotations:</h3>
* <ul>
* <li>{@code @Data} - Generates boilerplate code such as getters, setters, and toString.</li>
* <li>{@code @Builder} - Enables the builder pattern for constructing instances of this class.</li>
* <li>{@code @Service} - Marks this class as a Spring-managed service component.</li>
* </ul>
*
* <h3>Dependencies:</h3>
* <ul>
* <li>{@code RCommand} - Repository for accessing and persisting command entities.</li>
* <li>{@code SCropI} - Service for managing crops, used for operations involving crop data.</li>
* <li>{@code MCommand} - Mapper for converting between entity and DTO representations of commands.</li>
* </ul>
*
* <h3>Responsibilities:</h3>
* <ul>
* <li>Provides methods for creating, retrieving, updating, and deleting commands.</li>
* <li>Implements caching for frequently accessed commands to improve performance.</li>
* <li>Validates and processes business logic for commands before interacting with the repository.</li>
* </ul>
*
* <h3>Usage:</h3>
* <p>
* This service is typically used by controllers to handle HTTP requests related to commands,
* or by other services that depend on command-related operations.
* </p>
*
* @see SCommandI
* @see RCommand
* @see SCropI
* @see MCommand
*/
@Data
@Builder
@Service
Expand All @@ -31,18 +70,52 @@ public class SCommand implements SCommandI {
private final SCropI serviceCrop;
private final MCommand mapperCommand;

/**
* Constructs an instance of {@code SCommand} with the required dependencies.
*
* @param repositoryCommand the repository for command-related database operations
* @param serviceCrop the service responsible for crop-related logic
* @param mapperCommand the mapper for converting entities to DTOs and vice versa
*/
@Autowired
public SCommand(RCommand repositoryCommand, SCropI serviceCrop, MCommand mapperCommand) {
this.repositoryCommand = repositoryCommand;
this.serviceCrop = serviceCrop;
this.mapperCommand = mapperCommand;
}

/**
* Retrieves all commands from the repository and maps them to DTOs.
* <p>
* This method is cached to improve performance when retrieving the list of commands.
* The cache is identified by the key 'all_commands' under the 'commands' cache.
* </p>
*
* @return a list of {@code CommandDTO} objects representing all commands
* @throws Exception if no commands exist in the repository
*/
@Override
public List<Command> getAllCommands() {
return repositoryCommand.findAll();
@Cacheable(value = "commands", key = "'all_commands'")
public List<CommandDTO> getAllCommands() throws Exception {
return Optional.of(repositoryCommand.findAll())
.filter(commands -> !commands.isEmpty())
.map(crops -> crops.stream()
.map(mapperCommand::toDTO)
.collect(Collectors.toList()))
.orElseThrow(() -> new Exception("No existe ningún comando"));
}

/**
* Retrieves a command by its unique identifier and maps it to a DTO.
* <p>
* This method is cached to improve performance for retrieving individual commands.
* The cache is identified by the key pattern 'id_{id}' under the 'commands' cache.
* </p>
*
* @param id the unique identifier of the command to retrieve
* @return a {@code CommandDTO} representing the command with the specified ID
* @throws Exception if the command with the specified ID does not exist
*/
@Override
@Cacheable(value = "commands", key = "'id_'+#id")
public CommandDTO getCommandById(String id) throws Exception {
Expand All @@ -55,7 +128,21 @@ public CommandDTO getCommandById(String id) throws Exception {
.orElseThrow(() -> new Exception("El Comando no existe"));
}

/**
* Creates a new command based on the provided DTO, sets its creation date and status,
* and persists it in the repository.
*
* <p>
* This method assigns a default status of "PENDING" and records the current timestamp
* as the creation date in the format "yyyy-MM-dd HH:mm:ss".
* </p>
*
* @param commandDTO the {@code CommandDTO} containing the details of the command to create
* @return a {@code CommandDTO} representing the created command
* @throws IllegalStateException if a command with the same details already exists
*/
@Override
@Transactional
public CommandDTO createCommand(CommandDTO commandDTO) throws IllegalStateException {
return Optional.of(commandDTO)
.map(dto -> {
Expand All @@ -70,84 +157,22 @@ public CommandDTO createCommand(CommandDTO commandDTO) throws IllegalStateExcept
.orElseThrow(() -> new IllegalStateException("El Comando ya existe"));
}

@Override
public Command updateCommand(String id, Command upCommand) throws Exception {
if (!ObjectId.isValid(id)) {
throw new ApiException(new ApiResponse(
"El ID '" + id + "' no es válido. Asegúrate de que tiene 24 caracteres y solo incluye dígitos hexadecimales (0-9, a-f, A-F).",
HttpStatus.BAD_REQUEST.value()
));
}
Command exCommand = repositoryCommand.findById(new ObjectId(id)).orElseThrow(() -> new ApiException(
new ApiResponse("El Comando con ID '" + id + "' no fue encontrado.",
HttpStatus.NOT_FOUND.value())
));

if (upCommand == null) {
throw new IllegalArgumentException("El comando de actualización no puede ser nulo");
}

if (upCommand.getCrop() == null && serviceCrop.getCropById(upCommand.getCrop().toString()) != null) {
throw new IllegalArgumentException("El campo 'crop' no puede ser nulo");
}

if (upCommand.getDateCreated() == null) {
throw new IllegalArgumentException("El campo 'dateCreated' no puede ser nulo");
}

// Validar y convertir commandType a mayúsculas
if (upCommand.getCommandType() == null || upCommand.getCommandType().isEmpty()) {
throw new IllegalArgumentException("El campo 'commandType' no puede estar vacío");
} else {
exCommand.setCommandType(upCommand.getCommandType().toUpperCase());
}

// Validar y convertir status a mayúsculas
if (upCommand.getStatus() == null || upCommand.getStatus().isEmpty()) {
throw new IllegalArgumentException("El campo 'status' no puede estar vacío");
} else {
exCommand.setStatus(upCommand.getStatus().toUpperCase());
}

// Si se cumplen todas las validaciones, se procede a actualizar el comando
if (exCommand != null) {
exCommand.setCrop(upCommand.getCrop());
exCommand.setResponse(upCommand.getResponse());
exCommand.setDateCreated(upCommand.getDateCreated());
return repositoryCommand.save(exCommand);
} else {
return null;
}
/*


if (!upCommand.getCommandType().matches(exCommand.getCommandType())) {
throw new Exception(new ErrorResponse(
"El nombre '" + upCommand.getCommandType() + "' no es válido.",
HttpStatus.BAD_REQUEST.value()
));
}
if (!upCommand.ge) {
}
*/


}

@Override
@CacheEvict(value = "commands", key = "'id_'+#id")
public String deleteCommand(String id) throws Exception {
return Optional.of(getCommandById(id))
.map(command -> {
repositoryCommand.deleteById(new ObjectId(command.getId()));
return "El Comando con ID '" + id + "' fue eliminado.";
})
.orElseThrow(() -> new Exception("El Comando no existe."));
}

/**
* Executes a command by updating its status to "EXECUTED" and setting a response message.
*
* <p>
* This method updates the specified command with the current timestamp, sets its status to
* "EXECUTED", and records the provided response message.
* </p>
*
* @param id the ID of the command to execute
* @param response the response message to associate with the executed command
* @return a {@code CommandDTO} representing the updated command
* @throws Exception if the command cannot be found or updated
*/
@Override
@CachePut(value = "commands", key = "'id:'+#id")
public CommandDTO excuteCommand(String id, String response) throws Exception {
public CommandDTO executeCommand(String id, String response) throws Exception {
return Optional.of(getCommandById(id))
.map(commandDTO -> {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Expand All @@ -162,31 +187,59 @@ public CommandDTO excuteCommand(String id, String response) throws Exception {
.orElseThrow(() -> new Exception("El Comando no se pudo actualizar"));
}

/*




public Command executeCommand(String id, String response) {
Command command = repositoryCommand.findById(id).orElse(null);
if (command != null) {
command.setStatus("EXECUTED");
command.setDateExecuted(new Date());
command.setResponse(response);
return repositoryCommand.save(command);
}
return null;
/**
* Updates the specified command with new details provided in the update DTO.
*
* <p>
* This method updates fields in the command only if the corresponding fields in the
* update DTO are non-null. The existing values are retained for fields that are null in the update DTO.
* </p>
*
* @param id the ID of the command to update
* @param updateCommand the {@code CommandDTO} containing the updated details
* @return a {@code CommandDTO} representing the updated command
* @throws Exception if the command cannot be found or updated
*/
@Override
@Transactional
@CachePut(value = "commands", key = "'id_'+#id")
public CommandDTO updateCommand(String id, CommandDTO updateCommand) throws Exception {
CommandDTO existingCommand = getCommandById(id);
return Optional.of(updateCommand)
.map(dto -> {
existingCommand.setId(dto.getCommandType() != null ? dto.getCommandType() : existingCommand.getCommandType());
existingCommand.setResponse(dto.getResponse() != null ? dto.getResponse() : existingCommand.getResponse());
existingCommand.setCrop(dto.getCrop() != null ? dto.getCrop() : existingCommand.getCrop());
return existingCommand;
})
.map(mapperCommand::toEntity)
.map(repositoryCommand::save)
.map(mapperCommand::toDTO)
.orElseThrow(() -> new Exception("El Comando no se pudo actualizar"));
}



public List<Command> getCommandsByStatus(String status) {
return repositoryCommand.findByStatus(status);
/**
* Deletes the specified command by its ID.
*
* <p>
* This method removes the command from the repository and evicts the corresponding cache entry.
* </p>
*
* @param id the ID of the command to delete
* @return a confirmation message indicating the successful deletion
* @throws Exception if the command cannot be found
*/
@Override
@Transactional
@CacheEvict(value = "commands", key = "'id_'+#id")
public String deleteCommand(String id) throws Exception {
return Optional.of(getCommandById(id))
.map(command -> {
repositoryCommand.deleteById(new ObjectId(command.getId()));
return "El Comando con ID '" + id + "' fue eliminado.";
})
.orElseThrow(() -> new Exception("El Comando no existe."));
}

public List<Command> getCommandsByCropId(String cropId) {
return repositoryCommand.findByCrop_Id(cropId);
}

*/
}
Loading