Skip to content
Merged
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 @@ -3,9 +3,17 @@
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import static org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromCurrentRequest;

import java.io.IOException;
import java.net.URI;
import java.sql.SQLException;
import java.util.List;

Expand All @@ -18,7 +26,9 @@
import org.springframework.http.ResponseEntity;

import es.codeurjcstudents.pcmod.dto.ComponentDTO;
import es.codeurjcstudents.pcmod.dto.ImageDTO;
import es.codeurjcstudents.pcmod.model.Component;
import es.codeurjcstudents.pcmod.model.Image;
import es.codeurjcstudents.pcmod.service.ComponentsService;

@RestController
Expand Down Expand Up @@ -55,6 +65,28 @@ public ResponseEntity<Resource> getComponentImage(@PathVariable long id) throws
return ResponseEntity.ok().contentType(mediaType).body(imageFile);
}

@PostMapping("/")
public ResponseEntity<ComponentDTO> createComponent(@RequestBody ComponentDTO componentDTO) {

Component component = componentService.toDomain(componentDTO);
componentService.save(component);

URI location = fromCurrentRequest().path("/{id}").buildAndExpand(component.getId()).toUri();

return ResponseEntity.created(location).body(componentService.toDTO(component));
}

@PostMapping("/{id}/image")
public ResponseEntity<ImageDTO> addComponentImage(@PathVariable long id, @RequestParam MultipartFile imageFile)
throws IOException {

Image image = componentService.addComponentImage(id, imageFile);

URI location = fromCurrentRequest().buildAndExpand(id).toUri();

return ResponseEntity.created(location).body(new ImageDTO(image.getId()));
}

@DeleteMapping("/{id}")
public void deleteComponent(@PathVariable long id) {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package es.codeurjcstudents.pcmod.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import es.codeurjcstudents.pcmod.enums.ComponentType;

@RestController
@RequestMapping("/api/v1/component-types")
public class ComponentsTypeRestController {

@GetMapping
public ComponentType[] getComponentTypes() {
return ComponentType.values();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ public interface ComponentsRepository extends JpaRepository<Component, Long> {
@Query("SELECT c.image from Component c WHERE c.id = :id")
Optional<Image> findImageById(long id);

boolean existsByName(String name);

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
.exceptionHandling(handling -> handling.authenticationEntryPoint(unauthorizedHandlerJwt));

http.authorizeHttpRequests(authorize -> authorize
.requestMatchers(HttpMethod.POST, "/api/v1/components/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.DELETE, "/api/v1/components/**").hasRole("ADMIN")
.requestMatchers(HttpMethod.GET, "/api/v1/users/**").hasRole("REGISTERED_USER")
.requestMatchers(HttpMethod.POST, "/api/v1/users/*/image").hasRole("REGISTERED_USER")
.requestMatchers(HttpMethod.DELETE, "/api/v1/users/**").hasRole("REGISTERED_USER")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package es.codeurjcstudents.pcmod.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

Expand All @@ -10,6 +13,7 @@
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.stereotype.Service;

Expand All @@ -23,22 +27,20 @@
public class ComponentsService {

private final ComponentsRepository componentRepository;

private final ComponentMapper componentMapper;
private final ImageService imagesService;


public ComponentsService(ComponentsRepository componentRepository, ComponentMapper componentMapper) {
public ComponentsService(ComponentsRepository componentRepository, ComponentMapper componentMapper, ImageService imagesService) {
this.componentRepository = componentRepository;
this.componentMapper = componentMapper;
this.imagesService = imagesService;
}

public Page<Component> findAll(Pageable pageable) {
return componentRepository.findAll(pageable);
}

public ComponentDTO toDTO(Component component) {
return componentMapper.toDTO(component);
}

public List<Component> findTop3MoreRecent() {
return componentRepository.findTop3ByOrderByIdDesc();
}
Expand All @@ -59,6 +61,32 @@ public Resource getImageFile(long id) throws SQLException {

}

@PreAuthorize ("hasRole('ADMIN')")
public Component save(Component component) {

List<String> errors = validateComponent(component);

if (!errors.isEmpty()) {
throw new IllegalArgumentException("Validación fallida:\n• " + String.join("\n• ", errors));
}

return componentRepository.save(component);
}

@PreAuthorize("hasRole('ADMIN')")
public Image addComponentImage(long id, MultipartFile imageFile) throws IOException {

imagesService.validate(imageFile);

Component component = componentRepository.findById(id).orElseThrow();

Image image = imagesService.createImage(imageFile.getInputStream());

component.setImage(image);

return componentRepository.save(component).getImage();
}

@PreAuthorize("hasRole('ADMIN')")
public void delete(long id) {

Expand All @@ -71,4 +99,74 @@ public void delete(long id) {
}

}

public List<String> validateComponent(Component component) {

List<String> errors = new ArrayList<>();

if (component.getName() == null || component.getName().isEmpty()) {
errors.add("El nombre del componente es obligatorio.");
} else {
validateName(component, errors);
}

validateRequiredField(component.getDescription(), "La descripción es obligatoria.", errors);
validateRequiredField(component.getBrand(), "La marca es obligatoria.", errors);
validateRequiredField(component.getType().toString(), "El tipo es obligatoria.", errors);

if (component.getPrice() == null || component.getPrice().toString().isEmpty()) {
errors.add("El precio es obligatorio.");
} else {
validatePrice(component, errors);
}

if (component.getStock() == null || component.getStock().toString().isEmpty()) {
errors.add("El stock es obligatorio.");
} else {
validateStock(component, errors);
}

return errors;

}

private void validateRequiredField(String value, String message, List<String> errors) {

if (value == null || value.isEmpty()) {
errors.add(message);
}

}

public void validateName(Component component, List<String> errors) {

if (componentRepository.existsByName(component.getName())) {
errors.add("Ya existe un componente con ese nombre.");
}

}

public void validatePrice(Component component, List<String> errors) {

if (component.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
errors.add("El precio del producto ha de ser mayor de 0.00 €.");
}

}

public void validateStock(Component component, List<String> errors) {

if (component.getStock() < 0) {
errors.add("El stock del producto ha de ser 0 o mayor.");
}

}

public ComponentDTO toDTO(Component component) {
return componentMapper.toDTO(component);
}

public Component toDomain(ComponentDTO componentDTO) {
return componentMapper.toDomain(componentDTO);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void init() throws IOException {
"Memoria interna: 16 GB\r\n" + //
"Tipo de memoria interna: DDR4\r\n" + //
"Velocidad de memoria del reloj: 3200 MHz",
ComponentType.RAM, "Corsair", BigDecimal.valueOf(149.95), 2);
ComponentType.RAM, "Corsair", BigDecimal.valueOf(149.95), 0);
setComponentImage(component4, "/sample_images/corsair-vengeance.webp");
componentsRepository.save(component4);

Expand Down
Loading
Loading