Skip to content

Commit 59f77ac

Browse files
committed
add images to controllers
1 parent 4c90fc9 commit 59f77ac

17 files changed

Lines changed: 290 additions & 34 deletions

src/main/java/com/mastercloudapps/twitterscheduler/controller/PendingApi.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ public interface PendingApi {
4848
@ApiResponses(value = {
4949
@ApiResponse(responseCode = "201", description = "pending tweet successfully created",
5050
content = @Content(schema = @Schema(implementation = PendingTweetResponse.class))),
51+
@ApiResponse(responseCode = "400", description = "bad request (malformed image URLs included)"),
52+
@ApiResponse(responseCode = "422", description = "some image is not available"),
5153
@ApiResponse(responseCode = "500", description = "internal server error") })
52-
public PendingTweetResponse createPendingTweet(@RequestBody PendingTweetRequest request);
54+
public ResponseEntity<PendingTweetResponse> createPendingTweet(@RequestBody PendingTweetRequest request);
5355

5456
@Operation(
5557
summary = "Deletes a pending tweet and its images",
@@ -68,6 +70,6 @@ public interface PendingApi {
6870
@ApiResponse(responseCode = "200", description = "pending tweet successfully published",
6971
content = @Content(schema = @Schema(implementation = PublishOnDemandResponse.class))),
7072
@ApiResponse(responseCode = "404", description = "pending tweet not found"),
71-
@ApiResponse(responseCode = "405", description = "feature in progress") })
73+
@ApiResponse(responseCode = "405", description = "Feature in progress") })
7274
public ResponseEntity<PublishOnDemandResponse> publishOnDemand(@PathVariable Long id);
73-
}
75+
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/PendingApiController.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import java.util.Collection;
44
import java.util.stream.Collectors;
55

6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
68
import org.springframework.beans.factory.annotation.Autowired;
79
import org.springframework.dao.EmptyResultDataAccessException;
810
import org.springframework.http.HttpStatus;
@@ -11,14 +13,15 @@
1113
import org.springframework.web.bind.annotation.GetMapping;
1214
import org.springframework.web.bind.annotation.PostMapping;
1315
import org.springframework.web.bind.annotation.RequestMapping;
14-
import org.springframework.web.bind.annotation.ResponseStatus;
1516
import org.springframework.web.bind.annotation.RestController;
1617

1718
import com.mastercloudapps.twitterscheduler.application.usecase.CreatePendingTweetUseCase;
1819
import com.mastercloudapps.twitterscheduler.application.usecase.DeletePendingTweetUseCase;
1920
import com.mastercloudapps.twitterscheduler.application.usecase.FindAllPendingTweetUseCase;
2021
import com.mastercloudapps.twitterscheduler.application.usecase.FindOnePendingTweetUseCase;
2122
import com.mastercloudapps.twitterscheduler.application.usecase.PublishPendingTweetOnDemandUseCase;
23+
import com.mastercloudapps.twitterscheduler.controller.exception.ImageNotAvailableException;
24+
import com.mastercloudapps.twitterscheduler.controller.exception.MalformedImageUrlException;
2225
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingTweetRequest;
2326
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingTweetResponse;
2427
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PublishOnDemandResponse;
@@ -36,6 +39,8 @@
3639
@SecurityRequirement(name = "twitter-scheduler")
3740
public class PendingApiController implements PendingApi {
3841

42+
private static Logger logger = LoggerFactory.getLogger(PendingApiController.class);
43+
3944
private final CreatePendingTweetRequestMapper createPendingTweetRequestMapper;
4045

4146
private final PendingTweetResponseMapper pendingResponseMapper;
@@ -100,21 +105,32 @@ public ResponseEntity<PendingTweetResponse> getPendingTweetById(Long id) {
100105
findOnePendingTweetRequestMapper.mapRequest(id));
101106

102107
if(pendingTweet.isPresent()) {
103-
return new ResponseEntity<>(pendingResponseMapper.mapResponse(pendingTweet.get()), HttpStatus.OK);
108+
return new ResponseEntity<>(pendingResponseMapper.mapResponse(pendingTweet.get()),
109+
HttpStatus.OK);
104110
} else {
105111
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
106112
}
107113
}
108114

109115
@PostMapping
110-
@ResponseStatus(HttpStatus.CREATED)
111-
public PendingTweetResponse createPendingTweet(PendingTweetRequest request) {
116+
public ResponseEntity<PendingTweetResponse> createPendingTweet(PendingTweetRequest request) {
112117

113-
final var createPendingTweetRequest = createPendingTweetRequestMapper.mapRequest(request);
114-
115-
final var createPendingTweetResponse = createPendingTweetUseCase.create(createPendingTweetRequest);
118+
try {
119+
final var createPendingTweetRequest = createPendingTweetRequestMapper.mapRequest(request);
120+
121+
final var createPendingTweetResponse = createPendingTweetUseCase.create(createPendingTweetRequest);
116122

117-
return pendingResponseMapper.mapResponse(createPendingTweetResponse);
123+
return new ResponseEntity<>(pendingResponseMapper.mapResponse(createPendingTweetResponse),
124+
HttpStatus.CREATED);
125+
}
126+
catch(ImageNotAvailableException e) {
127+
logger.warn(e.getMessage());
128+
return new ResponseEntity<>(null, HttpStatus.UNPROCESSABLE_ENTITY);
129+
}
130+
catch(MalformedImageUrlException e) {
131+
logger.warn(e.getMessage());
132+
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
133+
}
118134
}
119135

120136
@DeleteMapping("/{id}")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.mastercloudapps.twitterscheduler.controller.exception;
2+
3+
public class ImageNotAvailableException extends RuntimeException {
4+
5+
private static final long serialVersionUID = 1607171163255641096L;
6+
7+
public ImageNotAvailableException(String url) {
8+
9+
super("Image not available in '" + url + "'");
10+
}
11+
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.mastercloudapps.twitterscheduler.controller.exception;
2+
3+
public class MalformedImageUrlException extends RuntimeException {
4+
5+
private static final long serialVersionUID = 1607171163255641096L;
6+
7+
public MalformedImageUrlException(String url) {
8+
9+
super("Bad url format: '" + url + "'");
10+
}
11+
12+
}
13+

src/main/java/com/mastercloudapps/twitterscheduler/controller/pending/dto/PendingImageResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
@NoArgsConstructor
1212
public class PendingImageResponse {
1313

14-
private Long pendingImageId;
14+
private Long id;
1515
private String url;
1616

1717
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/pending/dto/PendingTweetRequest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.mastercloudapps.twitterscheduler.controller.pending.dto;
22

3+
import java.util.List;
4+
35
import io.swagger.v3.oas.annotations.media.Schema;
46
import lombok.AllArgsConstructor;
57
import lombok.Builder;
@@ -15,10 +17,12 @@ public class PendingTweetRequest {
1517
@Schema(description = "Tweet content",
1618
example = "This is a test tweet", required = true)
1719
private String message;
18-
//private List<PendingImageRequest> images;
1920

2021
@Schema(description = "Publication date",
2122
example = "2022-04-01T10:00:00Z", required = true)
2223
private String publicationDate;
2324

25+
@Schema(description = "Images, specify url of each image", required = false)
26+
private List<PendingImageRequest> images;
27+
2428
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/pending/dto/PendingTweetResponse.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.mastercloudapps.twitterscheduler.controller.pending.dto;
22

3+
import java.util.List;
4+
35
import lombok.AllArgsConstructor;
46
import lombok.Builder;
57
import lombok.Data;
@@ -13,8 +15,8 @@ public class PendingTweetResponse {
1315

1416
private Long id;
1517
private String message;
16-
//private List<PendingImageResponse> images;
1718
private String publicationDate;
1819
private String createdAt;
20+
private List<PendingImageResponse> images;
1921

2022
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/pending/mapper/CreatePendingTweetRequestMapper.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,39 @@
22

33
import static java.util.Objects.requireNonNull;
44

5+
import java.io.IOException;
6+
import java.util.ArrayList;
7+
import java.util.List;
58
import java.util.Optional;
69

10+
import org.springframework.beans.factory.annotation.Autowired;
711
import org.springframework.stereotype.Component;
12+
import org.togglz.core.manager.FeatureManager;
813

914
import com.mastercloudapps.twitterscheduler.application.model.operation.CreatePendingTweetOperation;
15+
import com.mastercloudapps.twitterscheduler.configuration.featureflags.Features;
1016
import com.mastercloudapps.twitterscheduler.controller.exception.ExpiredPublicationDateException;
17+
import com.mastercloudapps.twitterscheduler.controller.exception.ImageNotAvailableException;
1118
import com.mastercloudapps.twitterscheduler.controller.exception.InvalidInputException;
19+
import com.mastercloudapps.twitterscheduler.controller.exception.MalformedImageUrlException;
20+
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingImageRequest;
1221
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingTweetRequest;
22+
import com.mastercloudapps.twitterscheduler.controller.validator.ImageAvailable;
1323
import com.mastercloudapps.twitterscheduler.domain.shared.NullableInstant;
1424

1525
@Component
1626
public class CreatePendingTweetRequestMapper {
27+
28+
private FeatureManager featureManager;
29+
30+
private ImageAvailable imageAvailableValidator;
31+
32+
@Autowired
33+
public CreatePendingTweetRequestMapper(final FeatureManager featureManager,
34+
final ImageAvailable imageAvailableValidator) {
35+
this.featureManager = featureManager;
36+
this.imageAvailableValidator = imageAvailableValidator;
37+
}
1738

1839
public CreatePendingTweetOperation mapRequest(final PendingTweetRequest request) {
1940

@@ -24,11 +45,17 @@ public CreatePendingTweetOperation mapRequest(final PendingTweetRequest request)
2445
final var message = this.mapMessage(request);
2546
final var publicationDate = this.mapPublicationDate(request);
2647

27-
return CreatePendingTweetOperation
48+
final var builder = CreatePendingTweetOperation
2849
.builder()
2950
.message(message)
30-
.publicationDate(publicationDate)
31-
.build();
51+
.publicationDate(publicationDate);
52+
53+
if(featureManager.isActive(Features.TWEETS_WITH_IMAGES)) {
54+
final var images = this.mapImages(request);
55+
builder.images(images);
56+
}
57+
58+
return builder.build();
3259
}
3360

3461
private String mapMessage(final PendingTweetRequest request) {
@@ -45,6 +72,7 @@ private NullableInstant mapPublicationDate(final PendingTweetRequest request) {
4572
throw new InvalidInputException("Missing required publicationDate");
4673
}
4774

75+
4876
String pubDate = requireNonNull(request.getPublicationDate(), "Publication date cannot be null.");
4977
NullableInstant instantPubDate = NullableInstant.fromUtcISO8601(pubDate);
5078
NullableInstant niNow = NullableInstant.now();
@@ -54,4 +82,26 @@ private NullableInstant mapPublicationDate(final PendingTweetRequest request) {
5482

5583
return instantPubDate;
5684
}
57-
}
85+
86+
private List<String> mapImages(final PendingTweetRequest request){
87+
88+
List<String> imagesOp = new ArrayList<>();
89+
90+
if (Optional.ofNullable(request.getImages()).isPresent()) {
91+
for (PendingImageRequest imageRequest : request.getImages()) {
92+
try {
93+
boolean available = imageAvailableValidator.validate(imageRequest.getUrl());
94+
if (!available) {
95+
throw new ImageNotAvailableException(imageRequest.getUrl());
96+
}
97+
imagesOp.add(imageRequest.getUrl());
98+
}
99+
catch (IOException e) {
100+
throw new MalformedImageUrlException(imageRequest.getUrl());
101+
}
102+
103+
}
104+
}
105+
return imagesOp;
106+
}
107+
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/pending/mapper/PendingTweetResponseMapper.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
package com.mastercloudapps.twitterscheduler.controller.pending.mapper;
22

33
import java.util.Optional;
4+
import java.util.stream.Collectors;
45

6+
import org.springframework.beans.factory.annotation.Autowired;
57
import org.springframework.stereotype.Component;
8+
import org.togglz.core.manager.FeatureManager;
69

10+
import com.mastercloudapps.twitterscheduler.configuration.featureflags.Features;
711
import com.mastercloudapps.twitterscheduler.controller.exception.InvalidInputException;
12+
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingImageResponse;
813
import com.mastercloudapps.twitterscheduler.controller.pending.dto.PendingTweetResponse;
914
import com.mastercloudapps.twitterscheduler.domain.pending.PendingTweet;
1015

1116
@Component
1217
public class PendingTweetResponseMapper {
18+
19+
private FeatureManager featureManager;
20+
21+
@Autowired
22+
public PendingTweetResponseMapper(final FeatureManager featureManager) {
23+
this.featureManager = featureManager;
24+
}
1325

1426
public PendingTweetResponse mapResponse(PendingTweet pendingTweet) {
1527

@@ -22,14 +34,24 @@ public PendingTweetResponse mapResponse(PendingTweet pendingTweet) {
2234
final var publicationDate = this.mapPublicationDate(pendingTweet);
2335
final var createdAt = this.mapCreatedAt(pendingTweet);
2436

25-
var responseBuilder = PendingTweetResponse
37+
var builder = PendingTweetResponse
2638
.builder()
2739
.id(id)
2840
.message(message)
2941
.publicationDate(publicationDate)
3042
.createdAt(createdAt);
3143

32-
return responseBuilder.build();
44+
if(featureManager.isActive(Features.TWEETS_WITH_IMAGES)) {
45+
Optional.ofNullable(pendingTweet.getImages())
46+
.ifPresent(images -> builder.images(images.stream()
47+
.map(image -> PendingImageResponse.builder()
48+
.id(image.id().id())
49+
.url(image.url().url())
50+
.build())
51+
.collect(Collectors.toList())));
52+
}
53+
54+
return builder.build();
3355
}
3456

3557
private Long mapId(final PendingTweet request) {
@@ -51,4 +73,4 @@ private String mapCreatedAt(final PendingTweet request) {
5173

5274
return request.createdAt().getFormatted();
5375
}
54-
}
76+
}

src/main/java/com/mastercloudapps/twitterscheduler/controller/tweet/dto/TweetImageResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
@NoArgsConstructor
1212
public class TweetImageResponse {
1313

14-
private Long tweetImageId;
14+
private Long id;
1515
private Long size;
1616
private String type;
1717
private Integer width;

0 commit comments

Comments
 (0)