MME-7 Add resource exists endpoint for images.
This commit is contained in:
parent
67a4a1339f
commit
02c7e8887e
@ -188,7 +188,7 @@ public class ImageControllerTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void putImage() throws Exception {
|
public void uploadImage() throws Exception {
|
||||||
final User owner = this.seedUser();
|
final User owner = this.seedUser();
|
||||||
final String accessToken = this.getAccessToken(owner);
|
final String accessToken = this.getAccessToken(owner);
|
||||||
try (final InputStream hal9000 = getHal9000InputStream()) {
|
try (final InputStream hal9000 = getHal9000InputStream()) {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import app.mealsmadeeasy.api.image.view.ImageView;
|
|||||||
import app.mealsmadeeasy.api.user.User;
|
import app.mealsmadeeasy.api.user.User;
|
||||||
import app.mealsmadeeasy.api.user.UserService;
|
import app.mealsmadeeasy.api.user.UserService;
|
||||||
import app.mealsmadeeasy.api.util.AccessDeniedView;
|
import app.mealsmadeeasy.api.util.AccessDeniedView;
|
||||||
|
import app.mealsmadeeasy.api.util.ResourceExistsView;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.core.io.InputStreamResource;
|
import org.springframework.core.io.InputStreamResource;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@ -61,8 +62,8 @@ public class ImageController {
|
|||||||
.body(new InputStreamResource(imageInputStream));
|
.body(new InputStreamResource(imageInputStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping
|
@PostMapping
|
||||||
public ResponseEntity<ImageView> putImage(
|
public ResponseEntity<ImageView> uploadImage(
|
||||||
@RequestParam MultipartFile image,
|
@RequestParam MultipartFile image,
|
||||||
@RequestParam String filename,
|
@RequestParam String filename,
|
||||||
@RequestParam(required = false) String alt,
|
@RequestParam(required = false) String alt,
|
||||||
@ -89,7 +90,7 @@ public class ImageController {
|
|||||||
return ResponseEntity.status(201).body(this.imageToViewConverter.convert(saved, principal, true));
|
return ResponseEntity.status(201).body(this.imageToViewConverter.convert(saved, principal, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{username}/{filename}")
|
@PutMapping("/{username}/{filename}")
|
||||||
public ResponseEntity<ImageView> updateInfo(
|
public ResponseEntity<ImageView> updateInfo(
|
||||||
@AuthenticationPrincipal User principal,
|
@AuthenticationPrincipal User principal,
|
||||||
@PathVariable String username,
|
@PathVariable String username,
|
||||||
@ -106,6 +107,16 @@ public class ImageController {
|
|||||||
return ResponseEntity.ok(this.imageToViewConverter.convert(updated, principal, true));
|
return ResponseEntity.ok(this.imageToViewConverter.convert(updated, principal, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{username}/{filename}/exists")
|
||||||
|
public ResponseEntity<ResourceExistsView> resourceExists(
|
||||||
|
@AuthenticationPrincipal User principal,
|
||||||
|
@PathVariable String username,
|
||||||
|
@PathVariable String filename
|
||||||
|
) {
|
||||||
|
final boolean exists = this.imageService.exists(principal, username, filename);
|
||||||
|
return ResponseEntity.ok(new ResourceExistsView(exists));
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{username}/{filename}")
|
@DeleteMapping("/{username}/{filename}")
|
||||||
public ResponseEntity<Object> deleteImage(
|
public ResponseEntity<Object> deleteImage(
|
||||||
@AuthenticationPrincipal User principal,
|
@AuthenticationPrincipal User principal,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ public class ImageEndpointAuthConfigurator implements EndpointAuthConfigurator {
|
|||||||
@Override
|
@Override
|
||||||
public void configure(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
public void configure(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
||||||
registry.requestMatchers(HttpMethod.GET, "/images/**").permitAll();
|
registry.requestMatchers(HttpMethod.GET, "/images/**").permitAll();
|
||||||
|
registry.requestMatchers(HttpMethod.GET, "/images/*/*/exists").authenticated();
|
||||||
registry.requestMatchers(HttpMethod.POST, "/images/**").authenticated();
|
registry.requestMatchers(HttpMethod.POST, "/images/**").authenticated();
|
||||||
registry.requestMatchers(HttpMethod.PUT, "/images/**").authenticated();
|
registry.requestMatchers(HttpMethod.PUT, "/images/**").authenticated();
|
||||||
registry.requestMatchers(HttpMethod.DELETE, "/images/**").authenticated();
|
registry.requestMatchers(HttpMethod.DELETE, "/images/**").authenticated();
|
||||||
|
|||||||
@ -6,4 +6,5 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
public interface ImageSecurity {
|
public interface ImageSecurity {
|
||||||
boolean isViewableBy(Image image, @Nullable User viewer);
|
boolean isViewableBy(Image image, @Nullable User viewer);
|
||||||
boolean isOwner(Image image, @Nullable User user);
|
boolean isOwner(Image image, @Nullable User user);
|
||||||
|
boolean canSeeExists(User viewer, String username, String filename);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,4 +45,9 @@ public class ImageSecurityImpl implements ImageSecurity {
|
|||||||
return image.getOwner() != null && user != null && Objects.equals(image.getOwner().getId(), user.getId());
|
return image.getOwner() != null && user != null && Objects.equals(image.getOwner().getId(), user.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canSeeExists(User viewer, String username, String filename) {
|
||||||
|
return viewer.getUsername().equals(username);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,8 @@ public interface ImageService {
|
|||||||
InputStream getImageContent(Image image, @Nullable User viewer) throws IOException;
|
InputStream getImageContent(Image image, @Nullable User viewer) throws IOException;
|
||||||
List<Image> getImagesOwnedBy(User user);
|
List<Image> getImagesOwnedBy(User user);
|
||||||
|
|
||||||
|
boolean exists(User viewer, String username, String filename);
|
||||||
|
|
||||||
Image update(Image image, User modifier, ImageUpdateSpec spec);
|
Image update(Image image, User modifier, ImageUpdateSpec spec);
|
||||||
|
|
||||||
void deleteImage(Image image, User modifier) throws IOException;
|
void deleteImage(Image image, User modifier) throws IOException;
|
||||||
|
|||||||
@ -196,6 +196,12 @@ public class S3ImageService implements ImageService {
|
|||||||
return new ArrayList<>(this.imageRepository.findAllByOwner(user));
|
return new ArrayList<>(this.imageRepository.findAllByOwner(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@PreAuthorize("@imageSecurity.canSeeExists(#viewer, #username, #filename)")
|
||||||
|
public boolean exists(User viewer, String username, String filename) {
|
||||||
|
return this.imageRepository.findByOwnerUsernameAndFilename(username, filename).isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@PreAuthorize("@imageSecurity.isOwner(#image, #modifier)")
|
@PreAuthorize("@imageSecurity.isOwner(#image, #modifier)")
|
||||||
public Image update(final Image image, User modifier, ImageUpdateSpec updateSpec) {
|
public Image update(final Image image, User modifier, ImageUpdateSpec updateSpec) {
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
package app.mealsmadeeasy.api.util;
|
||||||
|
|
||||||
|
public record ResourceExistsView(boolean exists) {}
|
||||||
Loading…
Reference in New Issue
Block a user