diff --git a/codiki-application/src/main/java/org/codiki/application/category/CategoryUseCases.java b/codiki-application/src/main/java/org/codiki/application/category/CategoryUseCases.java new file mode 100644 index 0000000..fad504e --- /dev/null +++ b/codiki-application/src/main/java/org/codiki/application/category/CategoryUseCases.java @@ -0,0 +1,21 @@ +package org.codiki.application.category; + +import java.util.Optional; +import java.util.UUID; + +import org.codiki.domain.category.model.Category; +import org.codiki.domain.category.port.CategoryPort; +import org.springframework.stereotype.Service; + +@Service +public class CategoryUseCases { + private final CategoryPort categoryPort; + + public CategoryUseCases(CategoryPort categoryPort) { + this.categoryPort = categoryPort; + } + + public Optional findById(UUID categoryId) { + return categoryPort.findById(categoryId); + } +} diff --git a/codiki-application/src/main/java/org/codiki/application/publication/PublicationCreationRequestValidator.java b/codiki-application/src/main/java/org/codiki/application/publication/PublicationCreationRequestValidator.java index 4b80371..1cd10a6 100644 --- a/codiki-application/src/main/java/org/codiki/application/publication/PublicationCreationRequestValidator.java +++ b/codiki-application/src/main/java/org/codiki/application/publication/PublicationCreationRequestValidator.java @@ -1,26 +1,26 @@ package org.codiki.application.publication; -import org.codiki.domain.publication.exception.PublicationCreationException; -import org.codiki.domain.publication.model.PublicationCreationRequest; +import org.codiki.domain.publication.exception.PublicationEditionException; +import org.codiki.domain.publication.model.PublicationEditionRequest; import org.springframework.stereotype.Component; @Component public class PublicationCreationRequestValidator { - void isValid(PublicationCreationRequest request) { + public void isValid(PublicationEditionRequest request) { if (request.title() == null) { - throw new PublicationCreationException("title cannot be null."); + throw new PublicationEditionException("title cannot be null"); } if (request.text() == null) { - throw new PublicationCreationException("text cannot be null."); + throw new PublicationEditionException("text cannot be null"); } if (request.description() == null) { - throw new PublicationCreationException("description cannot be null."); + throw new PublicationEditionException("description cannot be null"); } if (request.image() == null) { - throw new PublicationCreationException("image cannot be null."); + throw new PublicationEditionException("image cannot be null"); } } } diff --git a/codiki-application/src/main/java/org/codiki/application/publication/PublicationUpdateRequestValidator.java b/codiki-application/src/main/java/org/codiki/application/publication/PublicationUpdateRequestValidator.java new file mode 100644 index 0000000..7048d3c --- /dev/null +++ b/codiki-application/src/main/java/org/codiki/application/publication/PublicationUpdateRequestValidator.java @@ -0,0 +1,22 @@ +package org.codiki.application.publication; + +import static java.util.Objects.isNull; + +import org.codiki.domain.publication.exception.PublicationEditionException; +import org.codiki.domain.publication.model.PublicationEditionRequest; +import org.springframework.stereotype.Component; + +@Component +public class PublicationUpdateRequestValidator { + public void isValid(PublicationEditionRequest request) { + if ( + isNull(request.title()) && + isNull(request.text()) && + isNull(request.description()) && + isNull(request.image()) && + isNull(request.categoryId()) + ) { + throw new PublicationEditionException("no any field is filled"); + } + } +} diff --git a/codiki-application/src/main/java/org/codiki/application/publication/PublicationUseCases.java b/codiki-application/src/main/java/org/codiki/application/publication/PublicationUseCases.java index 6f3eb37..61ab22a 100644 --- a/codiki-application/src/main/java/org/codiki/application/publication/PublicationUseCases.java +++ b/codiki-application/src/main/java/org/codiki/application/publication/PublicationUseCases.java @@ -1,56 +1,63 @@ package org.codiki.application.publication; +import static java.util.Objects.isNull; import java.time.Clock; import java.time.ZonedDateTime; 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.user.UserUseCases; +import org.codiki.domain.category.exception.CategoryNotFoundException; import org.codiki.domain.category.model.Category; -import org.codiki.domain.category.port.CategoryPort; import org.codiki.domain.exception.AuthenticationRequiredException; -import org.codiki.domain.publication.exception.PublicationCreationException; +import org.codiki.domain.publication.exception.PublicationEditionException; +import org.codiki.domain.publication.exception.PublicationNotFoundException; +import org.codiki.domain.publication.exception.PublicationUpdateForbiddenException; import org.codiki.domain.publication.model.Publication; -import org.codiki.domain.publication.model.PublicationCreationRequest; +import org.codiki.domain.publication.model.PublicationEditionRequest; +import org.codiki.domain.publication.model.builder.PublicationBuilder; import org.codiki.domain.publication.port.PublicationPort; import org.codiki.domain.user.model.User; import org.springframework.stereotype.Service; @Service public class PublicationUseCases { - private final CategoryPort categoryPort; + private final CategoryUseCases categoryUseCases; private final KeyGenerator keyGenerator; private final PublicationPort publicationPort; private final PublicationCreationRequestValidator publicationCreationRequestValidator; + private final PublicationUpdateRequestValidator publicationUpdateRequestValidator; private final UserUseCases userUseCases; private final Clock clock; public PublicationUseCases( - CategoryPort categoryPort, + CategoryUseCases categoryUseCases, + Clock clock, KeyGenerator keyGenerator, - PublicationPort publicationPort, PublicationCreationRequestValidator publicationCreationRequestValidator, - UserUseCases userUseCases, - Clock clock + PublicationPort publicationPort, PublicationUpdateRequestValidator publicationUpdateRequestValidator, + UserUseCases userUseCases ) { - this.publicationCreationRequestValidator = publicationCreationRequestValidator; - this.userUseCases = userUseCases; - this.keyGenerator = keyGenerator; + this.categoryUseCases = categoryUseCases; this.clock = clock; - this.categoryPort = categoryPort; + this.keyGenerator = keyGenerator; + this.publicationCreationRequestValidator = publicationCreationRequestValidator; this.publicationPort = publicationPort; + this.publicationUpdateRequestValidator = publicationUpdateRequestValidator; + this.userUseCases = userUseCases; } - public Publication createPublication(PublicationCreationRequest request) { + public Publication createPublication(PublicationEditionRequest request) { publicationCreationRequestValidator.isValid(request); User authenticatedUser = userUseCases.getAuthenticatedUser() .orElseThrow(AuthenticationRequiredException::new); - Category category = categoryPort.findById(request.categoryId()) - .orElseThrow(() -> new PublicationCreationException( - String.format("No any category exists for id %s", request.categoryId()) + Category category = categoryUseCases.findById(request.categoryId()) + .orElseThrow(() -> new PublicationEditionException( + new CategoryNotFoundException(request.categoryId()) )); Publication newPublication = aPublication() @@ -69,4 +76,51 @@ public class PublicationUseCases { return newPublication; } + + public Publication updatePublication(UUID publicationId, PublicationEditionRequest request) { + publicationUpdateRequestValidator.isValid(request); + + Publication publicationToUpdate = publicationPort.findById(publicationId) + .orElseThrow(() -> new PublicationNotFoundException(publicationId)); + + User authenticatedUser = userUseCases.getAuthenticatedUser() + .orElseThrow(AuthenticationRequiredException::new); + + if (!publicationToUpdate.author().id().equals(authenticatedUser.id())) { + throw new PublicationUpdateForbiddenException(); + } + + PublicationBuilder publicationBuilder = aPublication().basedOn(publicationToUpdate); + + if (!isNull(request.title())) { + publicationBuilder.withTitle(request.title()); + } + + if (!isNull(request.text())) { + publicationBuilder.withText(request.text()); + } + + if (!isNull(request.description())) { + publicationBuilder.withDescription(request.description()); + } + + if (!isNull(request.image())) { + publicationBuilder.withImage(request.image()); + } + + if (!isNull(request.categoryId())) { + Category newCategory = categoryUseCases.findById(request.categoryId()) + .orElseThrow(() -> new PublicationEditionException( + new CategoryNotFoundException(request.categoryId()) + )); + + publicationBuilder.withCategory(newCategory); + } + + Publication updatedPublication = publicationBuilder.build(); + + publicationPort.save(updatedPublication); + + return updatedPublication; + } } diff --git a/codiki-domain/src/main/java/org/codiki/domain/category/exception/CategoryNotFoundException.java b/codiki-domain/src/main/java/org/codiki/domain/category/exception/CategoryNotFoundException.java new file mode 100644 index 0000000..f78fce6 --- /dev/null +++ b/codiki-domain/src/main/java/org/codiki/domain/category/exception/CategoryNotFoundException.java @@ -0,0 +1,11 @@ +package org.codiki.domain.category.exception; + +import java.util.UUID; + +import org.codiki.domain.exception.FunctionnalException; + +public class CategoryNotFoundException extends FunctionnalException { + public CategoryNotFoundException(UUID categoryId) { + super(String.format("No any category found for id %s.",categoryId)); + } +} diff --git a/codiki-domain/src/main/java/org/codiki/domain/exception/FunctionnalException.java b/codiki-domain/src/main/java/org/codiki/domain/exception/FunctionnalException.java index eed6d86..095110f 100644 --- a/codiki-domain/src/main/java/org/codiki/domain/exception/FunctionnalException.java +++ b/codiki-domain/src/main/java/org/codiki/domain/exception/FunctionnalException.java @@ -4,4 +4,12 @@ public abstract class FunctionnalException extends RuntimeException { public FunctionnalException(String message) { super(message); } + + public FunctionnalException(FunctionnalException cause) { + super(cause); + } + + public FunctionnalException(String message, FunctionnalException cause) { + super(message, cause); + } } diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationCreationException.java b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationCreationException.java deleted file mode 100644 index b1e2c27..0000000 --- a/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationCreationException.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.codiki.domain.publication.exception; - -import org.codiki.domain.exception.FunctionnalException; - -public class PublicationCreationException extends FunctionnalException { - public PublicationCreationException(String reason) { - super(String.format("Impossible to create a publication because : %s", reason)); - } -} diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationEditionException.java b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationEditionException.java new file mode 100644 index 0000000..ba2cd85 --- /dev/null +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationEditionException.java @@ -0,0 +1,13 @@ +package org.codiki.domain.publication.exception; + +import org.codiki.domain.exception.FunctionnalException; + +public class PublicationEditionException extends FunctionnalException { + public PublicationEditionException(String reason) { + super(String.format("Impossible to edit a publication because : %s.", reason)); + } + + public PublicationEditionException(FunctionnalException cause) { + super("Impossible to edit a publication due to a root cause.", cause); + } +} diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationNotFoundException.java b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationNotFoundException.java new file mode 100644 index 0000000..3e5a7bf --- /dev/null +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationNotFoundException.java @@ -0,0 +1,11 @@ +package org.codiki.domain.publication.exception; + +import java.util.UUID; + +import org.codiki.domain.exception.FunctionnalException; + +public class PublicationNotFoundException extends FunctionnalException { + public PublicationNotFoundException(UUID publicationId) { + super(String.format("No any publication found for id %s.", publicationId)); + } +} diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationUpdateForbiddenException.java b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationUpdateForbiddenException.java new file mode 100644 index 0000000..30eb782 --- /dev/null +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/exception/PublicationUpdateForbiddenException.java @@ -0,0 +1,9 @@ +package org.codiki.domain.publication.exception; + +import org.codiki.domain.exception.FunctionnalException; + +public class PublicationUpdateForbiddenException extends FunctionnalException { + public PublicationUpdateForbiddenException() { + super("Publication update is not allowed because you are not its owner."); + } +} diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationCreationRequest.java b/codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationEditionRequest.java similarity index 80% rename from codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationCreationRequest.java rename to codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationEditionRequest.java index 3963543..a456a9d 100644 --- a/codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationCreationRequest.java +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/model/PublicationEditionRequest.java @@ -2,7 +2,7 @@ package org.codiki.domain.publication.model; import java.util.UUID; -public record PublicationCreationRequest( +public record PublicationEditionRequest( String title, String text, String description, diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java b/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java index 3782bdc..5fcf281 100644 --- a/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/model/builder/PublicationBuilder.java @@ -82,4 +82,17 @@ public class PublicationBuilder { category ); } + + public PublicationBuilder basedOn(Publication publication) { + return new PublicationBuilder() + .withId(publication.id()) + .withKey(publication.key()) + .withTitle(publication.title()) + .withText(publication.text()) + .withDescription(publication.description()) + .withImage(publication.image()) + .withCreationDate(publication.creationDate()) + .withAuthor(publication.author()) + .withCategory(publication.category()); + } } diff --git a/codiki-domain/src/main/java/org/codiki/domain/publication/port/PublicationPort.java b/codiki-domain/src/main/java/org/codiki/domain/publication/port/PublicationPort.java index a060c32..a97d088 100644 --- a/codiki-domain/src/main/java/org/codiki/domain/publication/port/PublicationPort.java +++ b/codiki-domain/src/main/java/org/codiki/domain/publication/port/PublicationPort.java @@ -1,7 +1,12 @@ package org.codiki.domain.publication.port; +import java.util.Optional; +import java.util.UUID; + import org.codiki.domain.publication.model.Publication; public interface PublicationPort { void save(Publication publication); + + Optional findById(UUID publicationId); } diff --git a/codiki-exposition/src/main/java/org/codiki/exposition/configuration/GlobalControllerExceptionHandler.java b/codiki-exposition/src/main/java/org/codiki/exposition/configuration/GlobalControllerExceptionHandler.java index fbdaeb0..73271dc 100644 --- a/codiki-exposition/src/main/java/org/codiki/exposition/configuration/GlobalControllerExceptionHandler.java +++ b/codiki-exposition/src/main/java/org/codiki/exposition/configuration/GlobalControllerExceptionHandler.java @@ -1,12 +1,17 @@ package org.codiki.exposition.configuration; import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.FORBIDDEN; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.UNAUTHORIZED; +import org.codiki.domain.category.exception.CategoryNotFoundException; 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.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.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; @@ -37,4 +42,28 @@ public class GlobalControllerExceptionHandler { public void handleRefreshTokenExpiredException() { // Do nothing. } + + @ResponseStatus(BAD_REQUEST) + @ExceptionHandler(CategoryNotFoundException.class) + 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. + } } diff --git a/codiki-exposition/src/main/java/org/codiki/exposition/publication/PublicationController.java b/codiki-exposition/src/main/java/org/codiki/exposition/publication/PublicationController.java index 5c8072e..db69ecc 100644 --- a/codiki-exposition/src/main/java/org/codiki/exposition/publication/PublicationController.java +++ b/codiki-exposition/src/main/java/org/codiki/exposition/publication/PublicationController.java @@ -1,10 +1,14 @@ package org.codiki.exposition.publication; +import java.util.UUID; + import org.codiki.application.publication.PublicationUseCases; import org.codiki.domain.publication.model.Publication; -import org.codiki.domain.publication.model.PublicationCreationRequest; -import org.codiki.exposition.publication.model.PublicationCreationRequestDto; +import org.codiki.domain.publication.model.PublicationEditionRequest; +import org.codiki.exposition.publication.model.PublicationEditionRequestDto; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -19,9 +23,19 @@ public class PublicationController { } @PostMapping - public PublicationDto createPublication(@RequestBody PublicationCreationRequestDto requestDto) { - PublicationCreationRequest request = requestDto.toDomain(); + public PublicationDto createPublication(@RequestBody PublicationEditionRequestDto requestDto) { + PublicationEditionRequest request = requestDto.toDomain(); Publication newPublication = publicationUseCases.createPublication(request); return new PublicationDto(newPublication); } + + @PutMapping("/{publicationId}") + public PublicationDto updatePublication( + @PathVariable("publicationId") UUID publicationId, + @RequestBody PublicationEditionRequestDto requestDto + ) { + PublicationEditionRequest request = requestDto.toDomain(); + Publication updatedPublication = publicationUseCases.updatePublication(publicationId, request); + return new PublicationDto(updatedPublication); + } } diff --git a/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationCreationRequestDto.java b/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationCreationRequestDto.java deleted file mode 100644 index 9a88994..0000000 --- a/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationCreationRequestDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.codiki.exposition.publication.model; - -import java.util.UUID; - -import org.codiki.domain.publication.model.PublicationCreationRequest; - -public record PublicationCreationRequestDto( - String title, - String text, - String description, - String image, - UUID categoryId -) { - public PublicationCreationRequest toDomain() { - return new PublicationCreationRequest(title, text, description, image, categoryId); - } -} diff --git a/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationEditionRequestDto.java b/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationEditionRequestDto.java new file mode 100644 index 0000000..7f8edcb --- /dev/null +++ b/codiki-exposition/src/main/java/org/codiki/exposition/publication/model/PublicationEditionRequestDto.java @@ -0,0 +1,17 @@ +package org.codiki.exposition.publication.model; + +import java.util.UUID; + +import org.codiki.domain.publication.model.PublicationEditionRequest; + +public record PublicationEditionRequestDto( + String title, + String text, + String description, + String image, + UUID categoryId +) { + public PublicationEditionRequest toDomain() { + return new PublicationEditionRequest(title, text, description, image, categoryId); + } +} diff --git a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java index c40f597..e69bd7c 100644 --- a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java +++ b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/PublicationJpaAdapter.java @@ -1,5 +1,8 @@ package org.codiki.infrastructure.publication; +import java.util.Optional; +import java.util.UUID; + import org.codiki.domain.publication.model.Publication; import org.codiki.domain.publication.port.PublicationPort; import org.codiki.infrastructure.publication.model.PublicationEntity; @@ -19,4 +22,10 @@ public class PublicationJpaAdapter implements PublicationPort { PublicationEntity newPublicationEntity = new PublicationEntity(publication); repository.save(newPublicationEntity); } + + @Override + public Optional findById(UUID publicationId) { + return repository.findById(publicationId) + .map(PublicationEntity::toDomain); + } } diff --git a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/AuthorEntity.java b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/AuthorEntity.java index 360028f..0b22c0f 100644 --- a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/AuthorEntity.java +++ b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/AuthorEntity.java @@ -24,13 +24,17 @@ public class AuthorEntity { private UUID id; @Column(nullable = false) private String name; - private String image; +// private String image; public AuthorEntity(Author author) { this( author.id(), - author.name(), - author.image() + author.name() +// author.image() ); } + + public Author toDomain() { + return new Author(id, name, "image"); + } } diff --git a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java index df2ee4f..7a6df58 100644 --- a/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java +++ b/codiki-infrastructure/src/main/java/org/codiki/infrastructure/publication/model/PublicationEntity.java @@ -44,7 +44,7 @@ public class PublicationEntity { private AuthorEntity author; @ManyToOne(fetch = LAZY) @JoinColumn(name = "category_id") - private CategoryEntity categoryId; + private CategoryEntity category; public PublicationEntity(Publication publication) { this( @@ -59,4 +59,18 @@ public class PublicationEntity { new CategoryEntity(publication.category()) ); } + + public Publication toDomain() { + return new Publication( + id, + key, + title, + text, + description, + image, + creationDate, + author.toDomain(), + category.toDomain() + ); + } } diff --git a/rest-client-collection/Codiki/environments/localhost.bru b/rest-client-collection/Codiki/environments/localhost.bru index 3c3d33a..b283c11 100644 --- a/rest-client-collection/Codiki/environments/localhost.bru +++ b/rest-client-collection/Codiki/environments/localhost.bru @@ -1,3 +1,5 @@ vars { url: http://localhost:8080 + publicationId: 31301854-e7c2-4c92-8d91-e9e146a9048f + bearerToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1YWQ0NjJiOC04ZjllLTRhMjYtYmI4Ni1jNzRmZWY1ZDExYjYiLCJleHAiOjE3MTAyMzg3Mzh9.4OLDr87maWETWjjsue0rZp8A1r01Z2TE30RPJ3GwnyTybwWFDruV1h32kUrDwFRuA-tbUUHv_YnzDyy75sft3A }