Add dependency to pictures in publications.

This commit is contained in:
Florian THIERRY
2024-03-14 09:55:51 +01:00
parent 5c5304ff98
commit adc3cdf9a3
16 changed files with 62 additions and 40 deletions

View File

@@ -1,10 +1,10 @@
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;
import org.codiki.domain.picture.exception.PictureNotFoundException;
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;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -32,8 +32,7 @@ public class PictureUseCases {
picturePort.deleteById(pictureId); picturePort.deleteById(pictureId);
} }
public Picture findById(UUID pictureId) { public Optional<Picture> findById(UUID pictureId) {
return picturePort.findById(pictureId) return picturePort.findById(pictureId);
.orElseThrow(() -> new PictureNotFoundException(pictureId));
} }
} }

View File

@@ -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");
} }
} }
} }

View File

@@ -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");

View File

@@ -8,10 +8,13 @@ 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 +28,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 +53,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 +67,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 +116,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())) {

View File

@@ -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()));
} }
} }

View File

@@ -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
) { ) {

View File

@@ -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
) {} ) {}

View File

@@ -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())
; ;
} }

View File

@@ -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());

View File

@@ -6,6 +6,7 @@ import java.util.UUID;
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; 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.core.io.FileSystemResource;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@@ -39,7 +40,8 @@ public class PictureController {
@GetMapping(value = "/{pictureId}", produces = APPLICATION_OCTET_STREAM_VALUE) @GetMapping(value = "/{pictureId}", produces = APPLICATION_OCTET_STREAM_VALUE)
public FileSystemResource loadPicture(@PathVariable("pictureId") UUID pictureId) { public FileSystemResource loadPicture(@PathVariable("pictureId") UUID pictureId) {
Picture picture = pictureUseCases.findById(pictureId); Picture picture = pictureUseCases.findById(pictureId)
.orElseThrow(() -> new PictureNotFoundException(pictureId));
return new FileSystemResource(picture.contentFile()); return new FileSystemResource(picture.contentFile());
} }
} }

View File

@@ -13,8 +13,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 +25,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())
); );

View File

@@ -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);
} }
} }

View File

@@ -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()
); );
} }

View File

@@ -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()
); );

View File

@@ -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)
);

View File

@@ -1,7 +1,7 @@
vars { vars {
url: http://localhost:8080 url: http://localhost:8080
publicationId: fce1de27-11c6-4deb-a248-b63288c00037 publicationId: fce1de27-11c6-4deb-a248-b63288c00037
bearerToken: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1YWQ0NjJiOC04ZjllLTRhMjYtYmI4Ni1jNzRmZWY1ZDExYjYiLCJleHAiOjE3MTA0MDYxMzF9.FhAT0my_DfKKTcgpWA3cesv8WYNw36dV6O1ZYrNtW0NR3E9AQ_XP0hAw_GH1K4maMxIzToqzNrZVJ-ug-cIaCQ 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 pictureId: 65b660b7-66bb-4e4a-a62c-fd0ca101f972
} }