From 6e29ec7d58f148da9df057aec4f12c7fcc3fc40a Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 26 Jul 2024 10:38:11 -0500 Subject: [PATCH] S3ImageServiceTests all passing. --- .../api/image/S3ImageServiceTests.java | 63 ++++++++++++++++--- .../app/mealsmadeeasy/api/image/Image.java | 3 +- .../mealsmadeeasy/api/image/ImageService.java | 2 + .../api/image/S3ImageEntity.java | 6 +- .../api/image/S3ImageService.java | 31 ++++++--- .../api/user/ContainsUsersMatcher.java | 17 +++++ 6 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 src/testFixtures/java/app/mealsmadeeasy/api/user/ContainsUsersMatcher.java diff --git a/src/integrationTest/java/app/mealsmadeeasy/api/image/S3ImageServiceTests.java b/src/integrationTest/java/app/mealsmadeeasy/api/image/S3ImageServiceTests.java index c848488..400dbfb 100644 --- a/src/integrationTest/java/app/mealsmadeeasy/api/image/S3ImageServiceTests.java +++ b/src/integrationTest/java/app/mealsmadeeasy/api/image/S3ImageServiceTests.java @@ -22,13 +22,14 @@ import java.util.List; import java.util.Set; import static app.mealsmadeeasy.api.image.ContainsImagesMatcher.containsImages; +import static app.mealsmadeeasy.api.user.ContainsUsersMatcher.containsUsers; import static app.mealsmadeeasy.api.user.IsUserMatcher.isUser; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.Assert.assertThrows; @Testcontainers @SpringBootTest @@ -165,43 +166,89 @@ public class S3ImageServiceTests { @Test @DirtiesContext public void updateAlt() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + Image image = this.createHal9000(owner); + final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec(); + spec.setAlt("HAL 9000"); + image = this.imageService.update(image, owner, spec); + assertThat(image.getAlt(), is("HAL 9000")); } @Test @DirtiesContext public void updateCaption() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + Image image = this.createHal9000(owner); + final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec(); + spec.setCaption("HAL 9000 from 2001: A Space Odyssey"); + image = this.imageService.update(image, owner, spec); + assertThat(image.getCaption(), is("HAL 9000 from 2001: A Space Odyssey")); } @Test @DirtiesContext public void updateIsPublic() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + Image image = this.createHal9000(owner); + final ImageUpdateInfoSpec spec = new ImageUpdateInfoSpec(); + spec.setPublic(true); + image = this.imageService.update(image, owner, spec); + assertThat(image.isPublic(), is(true)); + } + + private Image addViewer(Image image, User owner, User viewer) { + final ImageUpdateInfoSpec spec0 = new ImageUpdateInfoSpec(); + spec0.setViewersToAdd(Set.of(viewer)); + return this.imageService.update(image, owner, spec0); } @Test @DirtiesContext public void addViewers() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + final User viewer = this.createTestUser("imageViewer"); + Image image = this.createHal9000(owner); + image = this.addViewer(image, owner, viewer); + assertThat(image.getViewers(), containsUsers(viewer)); } @Test @DirtiesContext public void removeViewers() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + final User viewer = this.createTestUser("imageViewer"); + Image image = this.createHal9000(owner); + image = this.addViewer(image, owner, viewer); + assertThat(image.getViewers(), containsUsers(viewer)); + + final ImageUpdateInfoSpec spec1 = new ImageUpdateInfoSpec(); + spec1.setViewersToRemove(Set.of(viewer)); + image = this.imageService.update(image, owner, spec1); + assertThat(image.getViewers(), empty()); } @Test @DirtiesContext public void clearAllViewers() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + final User viewer = this.createTestUser("imageViewer"); + Image image = this.createHal9000(owner); + image = this.addViewer(image, owner, viewer); + assertThat(image.getViewers(), containsUsers(viewer)); + + final ImageUpdateInfoSpec spec1 = new ImageUpdateInfoSpec(); + spec1.setClearAllViewers(true); + image = this.imageService.update(image, owner, spec1); + assertThat(image.getViewers(), empty()); } @Test @DirtiesContext public void deleteImage() throws Exception { - fail("TODO"); + final User owner = this.createTestUser("imageOwner"); + final Image image = this.createHal9000(owner); + this.imageService.deleteImage(image, owner); + assertThrows(ImageException.class, () -> this.imageService.getById(image.getId(), owner)); } } diff --git a/src/main/java/app/mealsmadeeasy/api/image/Image.java b/src/main/java/app/mealsmadeeasy/api/image/Image.java index c231c03..7c956a9 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/Image.java +++ b/src/main/java/app/mealsmadeeasy/api/image/Image.java @@ -1,7 +1,6 @@ package app.mealsmadeeasy.api.image; import app.mealsmadeeasy.api.user.User; -import app.mealsmadeeasy.api.user.UserEntity; import org.jetbrains.annotations.Nullable; import java.time.LocalDateTime; @@ -17,5 +16,5 @@ public interface Image { @Nullable String getCaption(); User getOwner(); boolean isPublic(); - Set getViewers(); + Set getViewers(); } diff --git a/src/main/java/app/mealsmadeeasy/api/image/ImageService.java b/src/main/java/app/mealsmadeeasy/api/image/ImageService.java index 52aa7a9..c61c536 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/ImageService.java +++ b/src/main/java/app/mealsmadeeasy/api/image/ImageService.java @@ -14,7 +14,9 @@ public interface ImageService { Image create(User owner, String userFilename, InputStream inputStream, long objectSize, ImageCreateInfoSpec infoSpec) throws IOException, ImageException; + Image getById(long id, @Nullable User viewer) throws ImageException; Image getByOwnerAndFilename(User owner, String filename, User viewer) throws ImageException; + InputStream getImageContent(Image image, @Nullable User viewer) throws IOException; List getImagesOwnedBy(User user); diff --git a/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java b/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java index 07dd6a7..5079afb 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java +++ b/src/main/java/app/mealsmadeeasy/api/image/S3ImageEntity.java @@ -135,7 +135,11 @@ public class S3ImageEntity implements Image { } @Override - public Set getViewers() { + public Set getViewers() { + return Set.copyOf(this.viewers); + } + + public Set getViewerEntities() { return this.viewers; } diff --git a/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java b/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java index b236b2e..3b83913 100644 --- a/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java +++ b/src/main/java/app/mealsmadeeasy/api/image/S3ImageService.java @@ -5,6 +5,7 @@ import app.mealsmadeeasy.api.image.spec.ImageUpdateInfoSpec; import app.mealsmadeeasy.api.s3.S3Manager; import app.mealsmadeeasy.api.user.User; import app.mealsmadeeasy.api.user.UserEntity; +import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; @@ -12,9 +13,7 @@ import org.springframework.stereotype.Service; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -75,9 +74,11 @@ public class S3ImageService implements ImageService { if (spec.getPublic() != null) { entity.setPublic(spec.getPublic()); } + final Set viewers = new HashSet<>(entity.getViewerEntities()); for (final User viewerToAdd : spec.getViewersToAdd()) { - entity.getViewers().add((UserEntity) viewerToAdd); + viewers.add((UserEntity) viewerToAdd); } + entity.setViewers(viewers); } @Override @@ -105,6 +106,14 @@ public class S3ImageService implements ImageService { return this.imageRepository.save(draft); } + @Override + @PostAuthorize("@imageSecurity.isViewableBy(returnObject, #viewer)") + public Image getById(long id, @Nullable User viewer) throws ImageException { + return this.imageRepository.findById(id).orElseThrow(() -> new ImageException( + ImageException.Type.INVALID_ID, "No Image with id: " + id + )); + } + @Override @PostAuthorize("@imageSecurity.isViewableBy(returnObject, #viewer)") public Image getByOwnerAndFilename(User owner, String filename, User viewer) throws ImageException { @@ -131,11 +140,15 @@ public class S3ImageService implements ImageService { public Image update(final Image image, User modifier, ImageUpdateInfoSpec updateSpec) { S3ImageEntity entity = (S3ImageEntity) image; this.transferFromSpec(entity, updateSpec); - for (final User toRemove : updateSpec.getViewersToRemove()) { - entity.getViewers().remove((UserEntity) toRemove); - } - if (updateSpec.getClearAllViewers() != null) { - entity.getViewers().clear(); + final @Nullable Boolean clearAllViewers = updateSpec.getClearAllViewers(); + if (clearAllViewers != null && clearAllViewers) { + entity.setViewers(Set.of()); + } else { + final Set viewers = new HashSet<>(entity.getViewerEntities()); + for (final User toRemove : updateSpec.getViewersToRemove()) { + viewers.remove((UserEntity) toRemove); + } + entity.setViewers(viewers); } return this.imageRepository.save(entity); } diff --git a/src/testFixtures/java/app/mealsmadeeasy/api/user/ContainsUsersMatcher.java b/src/testFixtures/java/app/mealsmadeeasy/api/user/ContainsUsersMatcher.java new file mode 100644 index 0000000..11dc151 --- /dev/null +++ b/src/testFixtures/java/app/mealsmadeeasy/api/user/ContainsUsersMatcher.java @@ -0,0 +1,17 @@ +package app.mealsmadeeasy.api.user; + +import app.mealsmadeeasy.api.matchers.ContainsItemsMatcher; + +import java.util.List; + +public class ContainsUsersMatcher extends ContainsItemsMatcher { + + public static ContainsUsersMatcher containsUsers(User... allExpected) { + return new ContainsUsersMatcher(allExpected); + } + + private ContainsUsersMatcher(User... allExpected) { + super(List.of(allExpected), o -> o instanceof User, User::getId); + } + +}