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