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
@@ -0,0 +1,5 @@
package es.codeurjcstudents.pcmod.dto;

public record ImageDTO(
Long id) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package es.codeurjcstudents.pcmod.dto;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

import es.codeurjcstudents.pcmod.model.Image;

@Mapper(componentModel = "spring")
public interface ImageMapper {

ImageDTO toDTO(Image image);

@Mapping(target = "imageFile", ignore = true)
Image toDomain(ImageDTO imageDTO);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package es.codeurjcstudents.pcmod.model;

import java.sql.Blob;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;

@Entity
public class Image {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Lob
private Blob imageFile;

public Image() {
}

public Image(Blob imageFile) {
this.imageFile = imageFile;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Blob getImageFile() {
return imageFile;
}

public void setImageFile(Blob imageFile) {
this.imageFile = imageFile;
}

@Override
public String toString() {
return "Image [id=" + id + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package es.codeurjcstudents.pcmod.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import es.codeurjcstudents.pcmod.model.Image;

public interface ImageRepository extends JpaRepository<Image, Long> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public class DatabaseInitializer {
@Autowired
private ComponentsRepository componentsRepository;

@Autowired
private ImageService imageService;

@PostConstruct
public void init() {

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

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.sql.rowset.serial.SerialBlob;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import es.codeurjcstudents.pcmod.dto.ComponentMapper;
import es.codeurjcstudents.pcmod.model.Image;
import es.codeurjcstudents.pcmod.repository.ImageRepository;

@Service
public class ImageService {

private static final long MAX_SIZE = 10 * 1024 * 1024; // 10MB
private static final List<String> ALLOWED_TYPES = List.of("image/jpeg", "image/png", "image/webp");

private final ImageRepository imageRepository;

@Autowired
private ComponentMapper componentMapper;

public ImageService(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}

public List<Image> findAll() {
return imageRepository.findAll();
}

public Image createImage(InputStream inputStream) throws IOException {

Image image = new Image();

try {
image.setImageFile(new SerialBlob(inputStream.readAllBytes()));
} catch (Exception e) {
throw new IOException("Failed to create image", e);
}

imageRepository.save(image);

return image;
}

public Image replaceImageFile(long id, InputStream inputStream) throws IOException {

Image image = imageRepository.findById(id).orElseThrow();

try {
image.setImageFile(new SerialBlob(inputStream.readAllBytes()));
} catch (Exception e) {
throw new IOException("Failed to create image", e);
}

imageRepository.save(image);

return image;
}

public Image deleteImage(long id) {

Image image = imageRepository.findById(id).orElseThrow();
imageRepository.deleteById(id);

return image;
}

public void validate(MultipartFile imageField) {

if (imageField.getSize() > MAX_SIZE) {
throw new IllegalArgumentException("El tamaño de la imagen no puede superar los 10MB.");
}

String contentType = imageField.getContentType();
if (contentType == null || !ALLOWED_TYPES.contains(contentType)) {
throw new IllegalArgumentException(
"El tipo de archivo no es válido. Solo se permiten imágenes JPEG, PNG y WebP.");
}

}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package es.codeurjcstudents.pcmod.integration;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

import org.springframework.core.io.Resource;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import org.testcontainers.containers.MySQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import es.codeurjcstudents.pcmod.model.Image;
import es.codeurjcstudents.pcmod.repository.ImageRepository;
import es.codeurjcstudents.pcmod.service.ImageService;

@Tag("server-integration")
@SpringBootTest
@Testcontainers
public class ImagesIntegrationTests {

@Container
private static final MySQLContainer<?> mysqlContainer = new MySQLContainer<>("mysql:8.4")
.withDatabaseName("TestDB")
.withUsername("TestDBUser")
.withPassword("TestDBPassword");

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url",
() -> mysqlContainer.getJdbcUrl() + "?useSSL=false&allowPublicKeyRetrieval=true");

registry.add("spring.datasource.username", mysqlContainer::getUsername);
registry.add("spring.datasource.password", mysqlContainer::getPassword);
registry.add("spring.datasource.driver-class-name", mysqlContainer::getDriverClassName);
}

@Autowired
private ImageService imageService;

@Autowired
private ImageRepository imageRepository;

@BeforeEach
void setUp() {
imageRepository.deleteAll();
imageRepository.save(new Image());
imageRepository.save(new Image());
imageRepository.save(new Image());
}

@Test
void createImages() throws IOException {

imageRepository.deleteAll();

List<Image> imageList = imageService.findAll();
assertEquals(0, imageList.size());

Resource imagePath1 = new ClassPathResource("/sample_images/i5-12400f.webp");
Image image1 = imageService.createImage(imagePath1.getInputStream());

Resource imagePath2 = new ClassPathResource("/sample_images/kingston-nv3.webp");
Image image2 = imageService.createImage(imagePath2.getInputStream());

imageList = imageService.findAll();
assertEquals(2, imageList.size());

List<Long> idList = imageList.stream().map(Image::getId).toList();
assertTrue(idList.contains(image1.getId()));
assertTrue(idList.contains(image2.getId()));

}

@Test
void replaceImage() throws IOException, SQLException {

imageRepository.deleteAll();

Resource originalPath = new ClassPathResource("/sample_images/kingston-nv3.webp");
byte[] originalBytes = originalPath.getInputStream().readAllBytes();
Image image = imageService.createImage(originalPath.getInputStream());

Resource replacementPath = new ClassPathResource("/sample_images/i5-12400f.webp");
byte[] expectedBytes = replacementPath.getInputStream().readAllBytes();

Image updatedImage = imageService.replaceImageFile(image.getId(), replacementPath.getInputStream());
byte[] updatedBytes = updatedImage.getImageFile().getBytes(1, (int) updatedImage.getImageFile().length());

assertEquals(image.getId(), updatedImage.getId());
assertFalse(Arrays.equals(originalBytes, updatedBytes));
assertArrayEquals(expectedBytes, updatedBytes);

}

@Test
void deleteImage() throws IOException {

Long imageToDelete = imageRepository.findAll().getFirst().getId();
imageService.deleteImage(imageToDelete);

List<Image> imageList = imageService.findAll();
assertEquals(2, imageList.size());

}

}
Loading
Loading