Compare commits
5 Commits
0b00f9b0aa
...
fb13cfd74d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb13cfd74d | ||
|
|
8d8a220fa0 | ||
|
|
adc3cdf9a3 | ||
|
|
5c5304ff98 | ||
|
|
a872a9fe33 |
@@ -1,6 +1,7 @@
|
||||
package org.codiki.application.picture;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.codiki.domain.picture.model.builder.PictureBuilder.aPicture;
|
||||
@@ -30,4 +31,8 @@ public class PictureUseCases {
|
||||
public void deletePicture(UUID pictureId) {
|
||||
picturePort.deleteById(pictureId);
|
||||
}
|
||||
|
||||
public Optional<Picture> findById(UUID pictureId) {
|
||||
return picturePort.findById(pictureId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ public class PublicationCreationRequestValidator {
|
||||
throw new PublicationEditionException("description cannot be null");
|
||||
}
|
||||
|
||||
if (request.image() == null) {
|
||||
throw new PublicationEditionException("image cannot be null");
|
||||
if (request.pictureId() == null) {
|
||||
throw new PublicationEditionException("pictureId cannot be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ public class PublicationUpdateRequestValidator {
|
||||
isNull(request.title()) &&
|
||||
isNull(request.text()) &&
|
||||
isNull(request.description()) &&
|
||||
isNull(request.image()) &&
|
||||
isNull(request.pictureId()) &&
|
||||
isNull(request.categoryId())
|
||||
) {
|
||||
throw new PublicationEditionException("no any field is filled");
|
||||
|
||||
@@ -3,15 +3,19 @@ package org.codiki.application.publication;
|
||||
import static java.util.Objects.isNull;
|
||||
import java.time.Clock;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.codiki.domain.publication.model.builder.AuthorBuilder.anAuthor;
|
||||
import static org.codiki.domain.publication.model.builder.PublicationBuilder.aPublication;
|
||||
import org.codiki.application.category.CategoryUseCases;
|
||||
import org.codiki.application.picture.PictureUseCases;
|
||||
import org.codiki.application.user.UserUseCases;
|
||||
import org.codiki.domain.category.exception.CategoryNotFoundException;
|
||||
import org.codiki.domain.category.model.Category;
|
||||
import org.codiki.domain.exception.AuthenticationRequiredException;
|
||||
import org.codiki.domain.picture.exception.PictureNotFoundException;
|
||||
import org.codiki.domain.picture.model.Picture;
|
||||
import org.codiki.domain.publication.exception.PublicationEditionException;
|
||||
import org.codiki.domain.publication.exception.PublicationNotFoundException;
|
||||
import org.codiki.domain.publication.exception.PublicationUpdateForbiddenException;
|
||||
@@ -25,19 +29,22 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class PublicationUseCases {
|
||||
private final CategoryUseCases categoryUseCases;
|
||||
private final Clock clock;
|
||||
private final KeyGenerator keyGenerator;
|
||||
private final PictureUseCases pictureUseCases;
|
||||
private final PublicationPort publicationPort;
|
||||
private final PublicationCreationRequestValidator publicationCreationRequestValidator;
|
||||
private final PublicationUpdateRequestValidator publicationUpdateRequestValidator;
|
||||
private final UserUseCases userUseCases;
|
||||
private final Clock clock;
|
||||
|
||||
public PublicationUseCases(
|
||||
CategoryUseCases categoryUseCases,
|
||||
Clock clock,
|
||||
KeyGenerator keyGenerator,
|
||||
PictureUseCases pictureUseCases,
|
||||
PublicationCreationRequestValidator publicationCreationRequestValidator,
|
||||
PublicationPort publicationPort, PublicationUpdateRequestValidator publicationUpdateRequestValidator,
|
||||
PublicationPort publicationPort,
|
||||
PublicationUpdateRequestValidator publicationUpdateRequestValidator,
|
||||
UserUseCases userUseCases
|
||||
) {
|
||||
this.categoryUseCases = categoryUseCases;
|
||||
@@ -47,6 +54,7 @@ public class PublicationUseCases {
|
||||
this.publicationPort = publicationPort;
|
||||
this.publicationUpdateRequestValidator = publicationUpdateRequestValidator;
|
||||
this.userUseCases = userUseCases;
|
||||
this.pictureUseCases = pictureUseCases;
|
||||
}
|
||||
|
||||
public Publication createPublication(PublicationEditionRequest request) {
|
||||
@@ -60,13 +68,18 @@ public class PublicationUseCases {
|
||||
new CategoryNotFoundException(request.categoryId())
|
||||
));
|
||||
|
||||
Picture picture = pictureUseCases.findById(request.pictureId())
|
||||
.orElseThrow(() -> new PublicationEditionException(
|
||||
new PictureNotFoundException(request.pictureId())
|
||||
));
|
||||
|
||||
Publication newPublication = aPublication()
|
||||
.withId(UUID.randomUUID())
|
||||
.withKey(keyGenerator.generateKey())
|
||||
.withTitle(request.title())
|
||||
.withText(request.text())
|
||||
.withDescription(request.description())
|
||||
.withImage(request.image())
|
||||
.withPicture(picture)
|
||||
.withCreationDate(ZonedDateTime.now(clock))
|
||||
.withAuthor(anAuthor().basedOn(authenticatedUser).build())
|
||||
.withCategory(category)
|
||||
@@ -104,8 +117,12 @@ public class PublicationUseCases {
|
||||
publicationBuilder.withDescription(request.description());
|
||||
}
|
||||
|
||||
if (!isNull(request.image())) {
|
||||
publicationBuilder.withImage(request.image());
|
||||
if (!isNull(request.pictureId())) {
|
||||
Picture picture = pictureUseCases.findById(request.pictureId())
|
||||
.orElseThrow(() -> new PublicationEditionException(
|
||||
new PictureNotFoundException(request.pictureId())
|
||||
));
|
||||
publicationBuilder.withPicture(picture);
|
||||
}
|
||||
|
||||
if (!isNull(request.categoryId())) {
|
||||
@@ -137,4 +154,8 @@ public class PublicationUseCases {
|
||||
|
||||
publicationPort.delete(publicationToDelete);
|
||||
}
|
||||
|
||||
public Optional<Publication> findById(UUID publicationId) {
|
||||
return publicationPort.findById(publicationId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.codiki.domain.picture.exception;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.exception.FunctionnalException;
|
||||
|
||||
public class PictureNotFoundException extends FunctionnalException {
|
||||
public PictureNotFoundException(UUID pictureId) {
|
||||
super(String.format("Picture with id %s is not found.", pictureId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.codiki.domain.picture.exception;
|
||||
|
||||
import org.codiki.domain.exception.FunctionnalException;
|
||||
|
||||
public class PictureUploadException extends FunctionnalException {
|
||||
public PictureUploadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,6 @@ public class PublicationEditionException extends FunctionnalException {
|
||||
}
|
||||
|
||||
public PublicationEditionException(FunctionnalException cause) {
|
||||
super("Impossible to edit a publication due to a root cause.", cause);
|
||||
super(String.format("Impossible to edit a publication due to a root cause: %s.", cause.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.category.model.Category;
|
||||
import org.codiki.domain.picture.model.Picture;
|
||||
|
||||
public record Publication(
|
||||
UUID id,
|
||||
@@ -11,8 +12,8 @@ public record Publication(
|
||||
String title,
|
||||
String text,
|
||||
String description,
|
||||
String image,
|
||||
ZonedDateTime creationDate,
|
||||
Picture picture,
|
||||
Author author,
|
||||
Category category
|
||||
) {
|
||||
|
||||
@@ -6,6 +6,6 @@ public record PublicationEditionRequest(
|
||||
String title,
|
||||
String text,
|
||||
String description,
|
||||
String image,
|
||||
UUID pictureId,
|
||||
UUID categoryId
|
||||
) {}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class AuthorBuilder {
|
||||
return new AuthorBuilder()
|
||||
.withId(user.id())
|
||||
// .withName(user.name())
|
||||
// .withImage(user.image())
|
||||
// .withImage(user.pictureId())
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.codiki.domain.publication.model.builder;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.picture.model.Picture;
|
||||
import org.codiki.domain.publication.model.Author;
|
||||
import org.codiki.domain.category.model.Category;
|
||||
import org.codiki.domain.publication.model.Publication;
|
||||
@@ -13,7 +14,7 @@ public class PublicationBuilder {
|
||||
private String title;
|
||||
private String text;
|
||||
private String description;
|
||||
private String image;
|
||||
private Picture picture;
|
||||
private ZonedDateTime creationDate;
|
||||
private Author author;
|
||||
private Category category;
|
||||
@@ -49,8 +50,8 @@ public class PublicationBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public PublicationBuilder withImage(String image) {
|
||||
this.image = image;
|
||||
public PublicationBuilder withPicture(Picture picture) {
|
||||
this.picture = picture;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -76,8 +77,7 @@ public class PublicationBuilder {
|
||||
title,
|
||||
text,
|
||||
description,
|
||||
image,
|
||||
creationDate,
|
||||
creationDate, picture,
|
||||
author,
|
||||
category
|
||||
);
|
||||
@@ -90,7 +90,7 @@ public class PublicationBuilder {
|
||||
.withTitle(publication.title())
|
||||
.withText(publication.text())
|
||||
.withDescription(publication.description())
|
||||
.withImage(publication.image())
|
||||
.withPicture(publication.picture())
|
||||
.withCreationDate(publication.creationDate())
|
||||
.withAuthor(publication.author())
|
||||
.withCategory(publication.category());
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
</dependency>
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.springframework.boot</groupId>-->
|
||||
<!-- <artifactId>spring-boot-starter-data-jpa</artifactId>-->
|
||||
|
||||
@@ -11,73 +11,57 @@ import org.codiki.domain.exception.LoginFailureException;
|
||||
import org.codiki.domain.exception.RefreshTokenDoesNotExistException;
|
||||
import org.codiki.domain.exception.RefreshTokenExpiredException;
|
||||
import org.codiki.domain.exception.UserDoesNotExistException;
|
||||
import org.codiki.domain.picture.exception.PictureNotFoundException;
|
||||
import org.codiki.domain.picture.exception.PictureUploadException;
|
||||
import org.codiki.domain.publication.exception.PublicationEditionException;
|
||||
import org.codiki.domain.publication.exception.PublicationNotFoundException;
|
||||
import org.codiki.domain.publication.exception.PublicationUpdateForbiddenException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ProblemDetail;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@ControllerAdvice
|
||||
public class GlobalControllerExceptionHandler {
|
||||
|
||||
@ResponseStatus(BAD_REQUEST)
|
||||
@ExceptionHandler(LoginFailureException.class)
|
||||
public void handleLoginFailureException() {
|
||||
// Do nothing.
|
||||
@RestControllerAdvice
|
||||
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
@ExceptionHandler({
|
||||
CategoryDeletionException.class,
|
||||
CategoryEditionException.class,
|
||||
CategoryNotFoundException.class,
|
||||
LoginFailureException.class,
|
||||
PublicationEditionException.class,
|
||||
PictureUploadException.class
|
||||
})
|
||||
public ProblemDetail handleBadRequestExceptions(Exception exception) {
|
||||
return buildProblemDetail(BAD_REQUEST, exception);
|
||||
}
|
||||
|
||||
@ResponseStatus(NOT_FOUND)
|
||||
@ExceptionHandler(UserDoesNotExistException.class)
|
||||
public void handleUserDoesNotExistException() {
|
||||
// Do nothing.
|
||||
@ExceptionHandler({
|
||||
UserDoesNotExistException.class,
|
||||
RefreshTokenDoesNotExistException.class,
|
||||
PublicationNotFoundException.class,
|
||||
PictureNotFoundException.class
|
||||
})
|
||||
public ProblemDetail handleNotFoundExceptions(Exception exception) {
|
||||
return buildProblemDetail(NOT_FOUND, exception);
|
||||
}
|
||||
|
||||
@ResponseStatus(NOT_FOUND)
|
||||
@ExceptionHandler(RefreshTokenDoesNotExistException.class)
|
||||
public void handleRefreshTokenDoesNotExistException() {
|
||||
// Do nothing.
|
||||
@ExceptionHandler({
|
||||
RefreshTokenExpiredException.class
|
||||
})
|
||||
public ProblemDetail handleUnauthorizedExceptions(Exception exception) {
|
||||
return buildProblemDetail(UNAUTHORIZED, exception);
|
||||
}
|
||||
|
||||
@ResponseStatus(UNAUTHORIZED)
|
||||
@ExceptionHandler(RefreshTokenExpiredException.class)
|
||||
public void handleRefreshTokenExpiredException() {
|
||||
// Do nothing.
|
||||
@ExceptionHandler({
|
||||
PublicationUpdateForbiddenException.class
|
||||
})
|
||||
public ProblemDetail handleForbiddenExceptions(Exception exception) {
|
||||
return buildProblemDetail(FORBIDDEN, exception);
|
||||
}
|
||||
|
||||
@ResponseStatus(BAD_REQUEST)
|
||||
@ExceptionHandler(CategoryNotFoundException.class)
|
||||
public void handleCategoryNotFoundException() {
|
||||
// Do nothing.
|
||||
private static ProblemDetail buildProblemDetail(HttpStatus forbidden, Exception exception) {
|
||||
return ProblemDetail.forStatusAndDetail(forbidden, exception.getMessage());
|
||||
}
|
||||
|
||||
@ResponseStatus(BAD_REQUEST)
|
||||
@ExceptionHandler(PublicationEditionException.class)
|
||||
public void handlePublicationEditionException() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@ResponseStatus(NOT_FOUND)
|
||||
@ExceptionHandler(PublicationNotFoundException.class)
|
||||
public void handlePublicationNotFoundException() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@ResponseStatus(FORBIDDEN)
|
||||
@ExceptionHandler(PublicationUpdateForbiddenException.class)
|
||||
public void handlePublicationUpdateForbiddenException() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@ResponseStatus(BAD_REQUEST)
|
||||
@ExceptionHandler(CategoryEditionException.class)
|
||||
public void handleCategoryEditionException() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@ResponseStatus(BAD_REQUEST)
|
||||
@ExceptionHandler(CategoryDeletionException.class)
|
||||
public void handleCategoryDeletionException() {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import static org.springframework.http.HttpMethod.OPTIONS;
|
||||
import static org.springframework.http.HttpMethod.POST;
|
||||
import static org.springframework.http.HttpMethod.PUT;
|
||||
import static org.springframework.security.config.http.SessionCreationPolicy.STATELESS;
|
||||
import org.codiki.domain.user.model.UserRole;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.Customizer;
|
||||
@@ -44,6 +45,8 @@ public class SecurityConfiguration {
|
||||
GET,
|
||||
"/api/health/check",
|
||||
"/api/categories",
|
||||
"/api/pictures/{pictureId}",
|
||||
"/api/publications/{publicationId}",
|
||||
"/error"
|
||||
).permitAll()
|
||||
.requestMatchers(
|
||||
@@ -54,15 +57,15 @@ public class SecurityConfiguration {
|
||||
.requestMatchers(
|
||||
POST,
|
||||
"/api/categories"
|
||||
).hasRole("ADMIN")
|
||||
).hasRole(UserRole.ADMIN.name())
|
||||
.requestMatchers(
|
||||
PUT,
|
||||
"/api/categories/{categoryId}"
|
||||
).hasRole("ADMIN")
|
||||
).hasRole(UserRole.ADMIN.name())
|
||||
.requestMatchers(
|
||||
DELETE,
|
||||
"/api/categories/{categoryId}"
|
||||
).hasRole("ADMIN")
|
||||
).hasRole(UserRole.ADMIN.name())
|
||||
.requestMatchers(OPTIONS).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
);
|
||||
|
||||
@@ -1,23 +1,44 @@
|
||||
package org.codiki.exposition.picture;
|
||||
|
||||
import static java.util.Objects.isNull;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.tika.mime.MimeType;
|
||||
import org.apache.tika.mime.MimeTypeException;
|
||||
import org.apache.tika.mime.MimeTypes;
|
||||
import org.codiki.domain.picture.exception.PictureUploadException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Component
|
||||
public class MultipartFileConverter {
|
||||
private final String tempPicturesForlderPath;
|
||||
private static final List<MimeType> ALLOWED_MIME_TYPES;
|
||||
|
||||
public MultipartFileConverter(@Value("${application.pictures.temp-path}") String tempPicturesForlderPath) {
|
||||
this.tempPicturesForlderPath = tempPicturesForlderPath;
|
||||
static {
|
||||
MimeTypes mimeTypes = MimeTypes.getDefaultMimeTypes();
|
||||
|
||||
try {
|
||||
ALLOWED_MIME_TYPES = List.of(
|
||||
mimeTypes.forName("image/png"),
|
||||
mimeTypes.forName("image/jpeg")
|
||||
);
|
||||
} catch (MimeTypeException exception) {
|
||||
throw new RuntimeException("An error occurred while loading allowed mime types.", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private final String tempPicturesFolderPath;
|
||||
|
||||
public MultipartFileConverter(@Value("${application.pictures.temp-path}") String tempPicturesFolderPath) {
|
||||
this.tempPicturesFolderPath = tempPicturesFolderPath;
|
||||
}
|
||||
|
||||
public File transformToFile(MultipartFile fileContent) {
|
||||
File pictureFile = new File(String.format("%s/%s", tempPicturesForlderPath, UUID.randomUUID()));
|
||||
File pictureFile = new File(buildPicturePath(fileContent));
|
||||
try {
|
||||
fileContent.transferTo(pictureFile);
|
||||
} catch (IOException e) {
|
||||
@@ -25,4 +46,34 @@ public class MultipartFileConverter {
|
||||
}
|
||||
return pictureFile;
|
||||
}
|
||||
|
||||
private String buildPicturePath(MultipartFile fileContent) {
|
||||
MimeType fileContentType = extractMimeType(fileContent);
|
||||
return String.format(
|
||||
"%s/%s%s",
|
||||
tempPicturesFolderPath,
|
||||
UUID.randomUUID(),
|
||||
fileContentType.getExtension()
|
||||
);
|
||||
}
|
||||
|
||||
private MimeType extractMimeType(MultipartFile fileContent) {
|
||||
MimeType result = null;
|
||||
try {
|
||||
result = MimeTypes.getDefaultMimeTypes()
|
||||
.forName(fileContent.getContentType());
|
||||
} catch (MimeTypeException exception) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (isNull(result) || !isAllowedMimeType(result)) {
|
||||
throw new PictureUploadException("Unable to upload the picture because its format is incorrect.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean isAllowedMimeType(MimeType mimeType) {
|
||||
return ALLOWED_MIME_TYPES.contains(mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,14 @@ package org.codiki.exposition.picture;
|
||||
import java.io.File;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
import org.codiki.application.picture.PictureUseCases;
|
||||
import org.codiki.domain.picture.exception.PictureNotFoundException;
|
||||
import org.codiki.domain.picture.model.Picture;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@@ -32,4 +37,11 @@ public class PictureController {
|
||||
Picture newPicture = pictureUseCases.createPicture(pictureFile);
|
||||
return newPicture.id();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/{pictureId}", produces = APPLICATION_OCTET_STREAM_VALUE)
|
||||
public FileSystemResource loadPicture(@PathVariable("pictureId") UUID pictureId) {
|
||||
Picture picture = pictureUseCases.findById(pictureId)
|
||||
.orElseThrow(() -> new PictureNotFoundException(pictureId));
|
||||
return new FileSystemResource(picture.contentFile());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ import java.util.UUID;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||
import org.codiki.application.publication.PublicationUseCases;
|
||||
import org.codiki.domain.publication.exception.PublicationNotFoundException;
|
||||
import org.codiki.domain.publication.model.Publication;
|
||||
import org.codiki.domain.publication.model.PublicationEditionRequest;
|
||||
import org.codiki.exposition.publication.model.PublicationDto;
|
||||
import org.codiki.exposition.publication.model.PublicationEditionRequestDto;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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.PutMapping;
|
||||
@@ -27,6 +29,13 @@ public class PublicationController {
|
||||
this.publicationUseCases = publicationUseCases;
|
||||
}
|
||||
|
||||
@GetMapping("/{publicationId}")
|
||||
public PublicationDto getById(@PathVariable("publicationId") UUID publicationId) {
|
||||
return publicationUseCases.findById(publicationId)
|
||||
.map(PublicationDto::new)
|
||||
.orElseThrow(() -> new PublicationNotFoundException(publicationId));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ResponseStatus(CREATED)
|
||||
public PublicationDto createPublication(@RequestBody PublicationEditionRequestDto requestDto) {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package org.codiki.exposition.publication;
|
||||
package org.codiki.exposition.publication.model;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.publication.model.Publication;
|
||||
import org.codiki.exposition.category.model.CategoryDto;
|
||||
import org.codiki.exposition.publication.model.AuthorDto;
|
||||
|
||||
public record PublicationDto(
|
||||
UUID id,
|
||||
@@ -13,8 +12,8 @@ public record PublicationDto(
|
||||
String title,
|
||||
String text,
|
||||
String description,
|
||||
String image,
|
||||
ZonedDateTime creationDate,
|
||||
UUID picture,
|
||||
AuthorDto author,
|
||||
CategoryDto category
|
||||
) {
|
||||
@@ -25,8 +24,8 @@ public record PublicationDto(
|
||||
publication.title(),
|
||||
publication.text(),
|
||||
publication.description(),
|
||||
publication.image(),
|
||||
publication.creationDate(),
|
||||
publication.picture().id(),
|
||||
new AuthorDto(publication.author()),
|
||||
new CategoryDto(publication.category())
|
||||
);
|
||||
@@ -8,10 +8,10 @@ public record PublicationEditionRequestDto(
|
||||
String title,
|
||||
String text,
|
||||
String description,
|
||||
String image,
|
||||
UUID pictureId,
|
||||
UUID categoryId
|
||||
) {
|
||||
public PublicationEditionRequest toDomain() {
|
||||
return new PublicationEditionRequest(title, text, description, image, categoryId);
|
||||
return new PublicationEditionRequest(title, text, description, pictureId, categoryId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.File;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.codiki.domain.picture.model.builder.PictureBuilder.aPicture;
|
||||
import org.codiki.domain.picture.exception.PictureNotFoundException;
|
||||
import org.codiki.domain.picture.exception.PictureStorageErrorException;
|
||||
import org.codiki.domain.picture.model.Picture;
|
||||
import org.codiki.domain.picture.port.PicturePort;
|
||||
@@ -35,7 +37,17 @@ public class PictureJpaAdapter implements PicturePort {
|
||||
@Override
|
||||
public Optional<Picture> findById(UUID pictureId) {
|
||||
return repository.findById(pictureId)
|
||||
.map(PictureEntity::toDomain);
|
||||
.map(PictureEntity::toDomain)
|
||||
.map(picture -> {
|
||||
File pictureFile = new File(String.format("%s/%s", pictureFolderPath, pictureId));
|
||||
if (!pictureFile.exists()) {
|
||||
throw new PictureNotFoundException(pictureId);
|
||||
}
|
||||
return aPicture()
|
||||
.basedOn(picture)
|
||||
.withContentFile(pictureFile)
|
||||
.build();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,13 +24,13 @@ public class AuthorEntity {
|
||||
private UUID id;
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
// private String image;
|
||||
// private String pictureId;
|
||||
|
||||
public AuthorEntity(Author author) {
|
||||
this(
|
||||
author.id(),
|
||||
author.name()
|
||||
// author.image()
|
||||
// author.pictureId()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.UUID;
|
||||
|
||||
import org.codiki.domain.publication.model.Publication;
|
||||
import org.codiki.infrastructure.category.model.CategoryEntity;
|
||||
import org.codiki.infrastructure.picture.model.PictureEntity;
|
||||
|
||||
import static jakarta.persistence.FetchType.LAZY;
|
||||
import jakarta.persistence.Column;
|
||||
@@ -36,10 +37,11 @@ public class PublicationEntity {
|
||||
@Column(nullable = false)
|
||||
private String description;
|
||||
@Column(nullable = false)
|
||||
private String image;
|
||||
@Column(nullable = false)
|
||||
private ZonedDateTime creationDate;
|
||||
@ManyToOne(fetch = LAZY)
|
||||
@JoinColumn(name = "picture_id")
|
||||
private PictureEntity picture;
|
||||
@ManyToOne(fetch = LAZY)
|
||||
@JoinColumn(name = "author_id")
|
||||
private AuthorEntity author;
|
||||
@ManyToOne(fetch = LAZY)
|
||||
@@ -53,8 +55,8 @@ public class PublicationEntity {
|
||||
publication.title(),
|
||||
publication.text(),
|
||||
publication.description(),
|
||||
publication.image(),
|
||||
publication.creationDate(),
|
||||
new PictureEntity(publication.picture()),
|
||||
new AuthorEntity(publication.author()),
|
||||
new CategoryEntity(publication.category())
|
||||
);
|
||||
@@ -67,8 +69,7 @@ public class PublicationEntity {
|
||||
title,
|
||||
text,
|
||||
description,
|
||||
image,
|
||||
creationDate,
|
||||
creationDate, picture.toDomain(),
|
||||
author.toDomain(),
|
||||
category.toDomain()
|
||||
);
|
||||
|
||||
@@ -9,6 +9,13 @@ import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface PublicationRepository extends JpaRepository<PublicationEntity, UUID> {
|
||||
@Query("SELECT p FROM PublicationEntity p JOIN FETCH p.author a JOIN FETCH p.category C WHERE p.id = :publicationId")
|
||||
@Query("""
|
||||
SELECT p
|
||||
FROM PublicationEntity p
|
||||
JOIN FETCH p.picture pi
|
||||
JOIN FETCH p.author a
|
||||
JOIN FETCH p.category c
|
||||
WHERE p.id = :publicationId
|
||||
""")
|
||||
Optional<PublicationEntity> findById(@Param("publicationId") UUID publicationId);
|
||||
}
|
||||
|
||||
@@ -31,24 +31,27 @@ CREATE TABLE IF NOT EXISTS category (
|
||||
);
|
||||
CREATE INDEX category_parent_category_id_idx ON category (parent_category_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS picture (
|
||||
id UUID NOT NULL,
|
||||
CONSTRAINT picture_pk PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS publication (
|
||||
id UUID NOT NULL,
|
||||
key VARCHAR(10) NOT NULL,
|
||||
title VARCHAR NOT NULL,
|
||||
text VARCHAR NOT NULL,
|
||||
description VARCHAR NOT NULL,
|
||||
image VARCHAR NOT NULL,
|
||||
creation_date TIMESTAMP NOT NULL,
|
||||
picture_id UUID NOT NULL,
|
||||
author_id UUID NOT NULL,
|
||||
category_id UUID NOT NULL,
|
||||
CONSTRAINT publication_pk PRIMARY KEY (id),
|
||||
CONSTRAINT publication_picture_id_fk FOREIGN KEY (picture_id) REFERENCES picture (id),
|
||||
CONSTRAINT publication_author_id_fk FOREIGN KEY (author_id) REFERENCES "user" (id),
|
||||
CONSTRAINT publication_category_id_fk FOREIGN KEY (category_id) REFERENCES category (id)
|
||||
);
|
||||
CREATE INDEX publication_picture_id_idx ON publication (picture_id);
|
||||
CREATE INDEX publication_author_id_idx ON publication (author_id);
|
||||
CREATE INDEX publication_category_id_idx ON publication (category_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS picture (
|
||||
id UUID NOT NULL,
|
||||
CONSTRAINT picture_pk PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -18,6 +18,7 @@
|
||||
<jakarta.servlet-api.version>6.0.0</jakarta.servlet-api.version>
|
||||
<java-jwt.version>4.4.0</java-jwt.version>
|
||||
<postgresql.version>42.7.0</postgresql.version>
|
||||
<tika-core.version>2.9.0</tika-core.version>
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
@@ -72,6 +73,11 @@
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${tika-core.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
vars {
|
||||
url: http://localhost:8080
|
||||
publicationId: fce1de27-11c6-4deb-a248-b63288c00037
|
||||
bearerToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1YWQ0NjJiOC04ZjllLTRhMjYtYmI4Ni1jNzRmZWY1ZDExYjYiLCJleHAiOjE3MTAzMzc2Njd9.ExV8xDeqqKk5WjIVb16NBqF1gPoRqx7uL4jQIhWjjY0QVhB5EAGdHMIbLr4s9Ck2f6z8U4sRlpPAQquDOr_9NA
|
||||
publicationId: e23831a6-9cc0-4f3d-9efa-7a1cae191cb1
|
||||
bearerToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1YWQ0NjJiOC04ZjllLTRhMjYtYmI4Ni1jNzRmZWY1ZDExYjYiLCJleHAiOjE3MTA0MDc5Mjd9.QdanZXjfLztIVJU-pRS3gZxnC4GIycyhmlCkhYSPchiXpeNzruw_GY3fH1_qshC_AjOCSqGmCq3X1S_zVFdodQ
|
||||
categoryId: 172fa901-3f4b-4540-92f3-1c15820e8ec9
|
||||
pictureId: 65b660b7-66bb-4e4a-a62c-fd0ca101f972
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user