Skip to content

Commit 256957b

Browse files
authored
Merge pull request #121 from SWM-Flash/integration
Integration
2 parents 064fb2d + c2ab9e7 commit 256957b

23 files changed

+543
-32
lines changed

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ dependencies {
6666

6767
// json
6868
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1'
69+
70+
// aws
71+
implementation 'io.awspring.cloud:spring-cloud-aws-starter:3.0.1'
72+
implementation platform('software.amazon.awssdk:bom:2.20.81')
73+
implementation 'software.amazon.awssdk:s3'
74+
implementation 'software.amazon.awssdk:mediaconvert'
6975
}
7076

7177
tasks.named('test') {

src/main/java/com/first/flash/climbing/problem/domain/QueryProblem.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public void setThumbnailInfo(final Long thumbnailSolutionId, final String imageU
103103
this.thumbnailSolutionId = thumbnailSolutionId;
104104
this.imageUrl = imageUrl;
105105
this.imageSource = imageSource;
106+
this.hasSolution = true;
106107
}
107108

108109
public void updateHoldInfo(final Long holdId, final String holdColorName, final String holdColorCode) {

src/main/java/com/first/flash/climbing/solution/application/SolutionSaveService.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import com.first.flash.climbing.solution.domain.PerceivedDifficultySetEvent;
1010
import com.first.flash.climbing.solution.domain.Solution;
1111
import com.first.flash.climbing.solution.domain.SolutionRepository;
12-
import com.first.flash.climbing.solution.domain.SolutionSavedEvent;
1312
import com.first.flash.climbing.solution.domain.dto.SolutionCreateRequestDto;
1413
import com.first.flash.global.event.Events;
1514
import com.first.flash.global.util.AuthUtil;
15+
import com.first.flash.upload.application.UploadService;
1616
import java.util.UUID;
1717
import lombok.RequiredArgsConstructor;
1818
import org.springframework.stereotype.Service;
@@ -25,27 +25,24 @@ public class SolutionSaveService {
2525

2626
private final MemberService memberService;
2727
private final SolutionRepository solutionRepository;
28+
private final UploadService uploadService;
2829

2930
@Transactional
3031
public SolutionWriteResponseDto saveSolution(final UUID problemId,
3132
final SolutionCreateRequestDto createRequestDto) {
3233
UUID id = AuthUtil.getId();
3334
Member member = memberService.findById(id);
34-
3535
PerceivedDifficulty perceivedDifficulty = createRequestDto.perceivedDifficulty();
3636
Solution solution = Solution.of(member.getNickName(), createRequestDto.review(),
37-
member.getInstagramId(), createRequestDto.thumbnailImageUrl(), createRequestDto.solvedDate(),
38-
createRequestDto.videoUrl(), problemId, member.getId(),
37+
member.getInstagramId(), createRequestDto.thumbnailImageUrl(),
38+
createRequestDto.solvedDate(), problemId, member.getId(),
3939
member.getProfileImageUrl(), perceivedDifficulty, member.getHeight(), member.getReach(),
4040
member.getGender());
4141
Events.raise(PerceivedDifficultySetEvent.of(solution.getProblemId(),
4242
perceivedDifficulty.getValue()));
4343

4444
Solution savedSolution = solutionRepository.save(solution);
45-
Events.raise(SolutionSavedEvent.of(savedSolution.getProblemId(), savedSolution.getId(),
46-
savedSolution.getSolutionDetail().getThumbnailImageUrl(),
47-
savedSolution.getUploaderDetail().getInstagramId()));
48-
45+
uploadService.uploadAndTranscodingVideo(createRequestDto.solutionVideo(), savedSolution.getId());
4946
return SolutionWriteResponseDto.toDto(savedSolution);
5047
}
5148

@@ -66,16 +63,11 @@ public SolutionWriteResponseDto saveUnregisteredMemberSolution(final UUID proble
6663
PerceivedDifficulty perceivedDifficulty = requestDto.perceivedDifficulty();
6764
Solution solution = Solution.of(requestDto.nickName(), requestDto.review(),
6865
requestDto.instagramId(), requestDto.thumbnailImageUrl(), requestDto.solvedDate(),
69-
requestDto.videoUrl(), problemId, member.getId(),
70-
requestDto.profileImageUrl(), perceivedDifficulty, member.getHeight(),
71-
member.getReach(), member.getGender());
66+
problemId, member.getId(), requestDto.profileImageUrl(), perceivedDifficulty,
67+
member.getHeight(), member.getReach(), member.getGender());
7268

7369
Solution savedSolution = solutionRepository.save(solution);
74-
Events.raise(PerceivedDifficultySetEvent.of(solution.getProblemId(),
75-
perceivedDifficulty.getValue()));
76-
Events.raise(SolutionSavedEvent.of(savedSolution.getProblemId(), savedSolution.getId(),
77-
savedSolution.getSolutionDetail().getThumbnailImageUrl(),
78-
savedSolution.getUploaderDetail().getInstagramId()));
70+
uploadService.uploadAndTranscodingVideo(requestDto.solutionVideo(), savedSolution.getId());
7971
return SolutionWriteResponseDto.toDto(savedSolution);
8072
}
8173
}

src/main/java/com/first/flash/climbing/solution/application/SolutionService.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,23 @@
44
import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent;
55
import com.first.flash.climbing.solution.application.dto.MySolutionFilter;
66
import com.first.flash.climbing.solution.application.dto.MySolutionsRequestDto;
7+
import com.first.flash.climbing.solution.application.dto.SolutionStatusUpdateRequestDto;
78
import com.first.flash.climbing.solution.application.dto.SolutionUpdateRequestDto;
89
import com.first.flash.climbing.solution.application.dto.SolutionWriteResponseDto;
910
import com.first.flash.climbing.solution.application.dto.SolutionsPageResponseDto;
1011
import com.first.flash.climbing.solution.application.dto.SolutionsResponseDto;
11-
import com.first.flash.climbing.solution.infrastructure.dto.MemberSolutionGroupDto;
1212
import com.first.flash.climbing.solution.domain.PerceivedDifficulty;
1313
import com.first.flash.climbing.solution.domain.PerceivedDifficultySetEvent;
1414
import com.first.flash.climbing.solution.domain.Solution;
1515
import com.first.flash.climbing.solution.domain.SolutionDeletedEvent;
1616
import com.first.flash.climbing.solution.domain.SolutionRepository;
17+
import com.first.flash.climbing.solution.domain.SolutionSavedEvent;
1718
import com.first.flash.climbing.solution.domain.SolutionUpdatedEvent;
1819
import com.first.flash.climbing.solution.domain.dto.SolutionResponseDto;
1920
import com.first.flash.climbing.solution.exception.exceptions.SolutionAccessDeniedException;
2021
import com.first.flash.climbing.solution.exception.exceptions.SolutionNotFoundException;
2122
import com.first.flash.climbing.solution.infrastructure.dto.DetailSolutionDto;
23+
import com.first.flash.climbing.solution.infrastructure.dto.MemberSolutionGroupDto;
2224
import com.first.flash.climbing.solution.infrastructure.paging.SolutionCursor;
2325
import com.first.flash.global.event.Events;
2426
import com.first.flash.global.util.AuthUtil;
@@ -109,6 +111,22 @@ public void deleteSolution(final Long id) {
109111
SolutionDeletedEvent.of(solution.getProblemId(), perceivedDifficulty.getValue()));
110112
}
111113

114+
@Transactional
115+
public SolutionWriteResponseDto updateSolutionStatus(final Long id,
116+
final SolutionStatusUpdateRequestDto requestDto) {
117+
Solution solution = findSolutionById(id);
118+
solution.updateStatus(requestDto.status());
119+
if (solution.hasFailed()) {
120+
return SolutionWriteResponseDto.toDto(solution);
121+
}
122+
123+
solution.updateVideoUrl(requestDto.videoUrl());
124+
Events.raise(SolutionSavedEvent.of(solution.getProblemId(), solution.getId(),
125+
solution.getSolutionDetail().getThumbnailImageUrl(),
126+
solution.getUploaderDetail().getInstagramId()));
127+
return SolutionWriteResponseDto.toDto(solution);
128+
}
129+
112130
@Transactional
113131
public void deleteByUploaderId(final UUID memberId) {
114132
solutionRepository.deleteByUploaderId(memberId);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.first.flash.climbing.solution.application.dto;
2+
3+
import com.first.flash.climbing.solution.domain.vo.SolutionVideoStatus;
4+
import com.first.flash.global.annotation.ValidEnum;
5+
6+
public record SolutionStatusUpdateRequestDto(
7+
@ValidEnum(enumClass = SolutionVideoStatus.class) SolutionVideoStatus status, String videoUrl) {
8+
9+
}

src/main/java/com/first/flash/climbing/solution/application/dto/SolutionWriteResponseDto.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
import com.first.flash.climbing.solution.domain.Solution;
44
import com.first.flash.climbing.solution.domain.vo.SolutionDetail;
5+
import com.first.flash.climbing.solution.domain.vo.SolutionVideoStatus;
56
import com.first.flash.climbing.solution.domain.vo.UploaderDetail;
67
import com.first.flash.global.util.AuthUtil;
78
import java.time.LocalDate;
89
import java.util.UUID;
910

1011
public record SolutionWriteResponseDto(Long id, String uploader, String review, String instagramId,
11-
String thumbnailImageUrl, String videoUrl, LocalDate solvedDate,
12+
String thumbnailImageUrl, String videoUrl,
13+
LocalDate solvedDate,
1214
UUID uploaderId, Boolean isUploader,
13-
String profileImageUrl) {
15+
String profileImageUrl, SolutionVideoStatus status) {
1416

1517
public static SolutionWriteResponseDto toDto(final Solution solution) {
1618
SolutionDetail solutionDetail = solution.getSolutionDetail();
@@ -22,6 +24,6 @@ public static SolutionWriteResponseDto toDto(final Solution solution) {
2224
solutionDetail.getReview(), uploaderDetail.getInstagramId(),
2325
solutionDetail.getThumbnailImageUrl(), solutionDetail.getVideoUrl(),
2426
solutionDetail.getSolvedDate(), uploaderDetail.getUploaderId(), isUploader,
25-
uploaderDetail.getProfileImageUrl());
27+
uploaderDetail.getProfileImageUrl(), solution.getVideoStatus());
2628
}
2729
}

src/main/java/com/first/flash/climbing/solution/application/dto/UnregisteredMemberSolutionCreateRequest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
import jakarta.validation.constraints.NotEmpty;
66
import jakarta.validation.constraints.NotNull;
77
import java.time.LocalDate;
8+
import org.springframework.web.multipart.MultipartFile;
89

910
public record UnregisteredMemberSolutionCreateRequest(
11+
MultipartFile solutionVideo,
1012
@NotEmpty(message = "닉네임은 필수입니다.") String nickName,
1113
@NotEmpty(message = "인스타그램 아이디는 필수입니다.") String instagramId,
1214
String review, String profileImageUrl,
1315
@NotEmpty(message = "썸네일 URL은 필수입니다.") String thumbnailImageUrl,
14-
@NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl,
1516
@NotNull(message = "풀이 일자 정보는 필수입니다.") LocalDate solvedDate,
1617
@NotNull(message = "체감 난이도는 필수입니다.")
1718
@ValidEnum(enumClass = PerceivedDifficulty.class) PerceivedDifficulty perceivedDifficulty) {

src/main/java/com/first/flash/climbing/solution/domain/Solution.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.first.flash.account.member.domain.Gender;
44
import com.first.flash.climbing.solution.domain.vo.SolutionDetail;
5+
import com.first.flash.climbing.solution.domain.vo.SolutionVideoStatus;
56
import com.first.flash.climbing.solution.domain.vo.UploaderDetail;
67
import com.first.flash.global.domain.BaseEntity;
78
import jakarta.persistence.CascadeType;
89
import jakarta.persistence.Column;
910
import jakarta.persistence.Entity;
11+
import jakarta.persistence.EnumType;
12+
import jakarta.persistence.Enumerated;
1013
import jakarta.persistence.GeneratedValue;
1114
import jakarta.persistence.GenerationType;
1215
import jakarta.persistence.Id;
@@ -37,6 +40,8 @@ public class Solution extends BaseEntity {
3740
private SolutionDetail solutionDetail;
3841
private UploaderDetail uploaderDetail;
3942
private Long optionalWeight;
43+
@Enumerated(EnumType.STRING)
44+
private SolutionVideoStatus videoStatus;
4045
@OneToMany(mappedBy = "solution", cascade = CascadeType.ALL, orphanRemoval = true)
4146
@ToString.Exclude
4247
private List<SolutionComment> comments = new ArrayList<>();
@@ -46,31 +51,47 @@ protected Solution(final String uploader, final String review, final String inst
4651
final String videoUrl, final UUID problemId, final UUID uploaderId,
4752
final String profileImageUrl, final PerceivedDifficulty perceivedDifficulty,
4853
final Double uploaderHeight,
49-
final Double uploaderReach, final Gender uploaderGender) {
54+
final Double uploaderReach, final Gender uploaderGender,
55+
final SolutionVideoStatus videoStatus) {
5056

5157
this.solutionDetail = SolutionDetail.of(review, thumbnailImageUrl, videoUrl,
5258
solvedDate, perceivedDifficulty);
5359
this.uploaderDetail = UploaderDetail.of(uploaderId, uploader, instagramId, profileImageUrl,
5460
uploaderHeight, uploaderReach, uploaderGender);
5561
this.optionalWeight = DEFAULT_OPTIONAL_WEIGHT;
62+
this.videoStatus = videoStatus;
5663
this.problemId = problemId;
5764
}
5865

5966
public static Solution of(final String uploader, final String review, final String instagramId,
6067
final String thumbnailImageUrl, final LocalDate solvedDate,
61-
final String videoUrl, final UUID problemId, final UUID uploaderId,
68+
final UUID problemId, final UUID uploaderId,
6269
final String profileImageUrl, final PerceivedDifficulty perceivedDifficulty,
6370
final Double uploaderHeight,
6471
final Double uploaderReach, final Gender uploaderGender) {
6572

66-
return new Solution(uploader, review, instagramId, thumbnailImageUrl, solvedDate, videoUrl,
73+
return new Solution(uploader, review, instagramId, thumbnailImageUrl, solvedDate, null,
6774
problemId, uploaderId,
68-
profileImageUrl, perceivedDifficulty, uploaderHeight, uploaderReach, uploaderGender);
75+
profileImageUrl, perceivedDifficulty, uploaderHeight, uploaderReach, uploaderGender,
76+
SolutionVideoStatus.PENDING);
6977
}
7078

71-
public void updateContentInfo(final String review, final String videoUrl, final String thumbnailImageUrl,
79+
public void updateContentInfo(final String review, final String videoUrl,
80+
final String thumbnailImageUrl,
7281
final LocalDate solvedDate, final PerceivedDifficulty perceivedDifficulty) {
7382
this.solutionDetail = SolutionDetail.of(review, thumbnailImageUrl, videoUrl,
7483
solvedDate, perceivedDifficulty);
7584
}
85+
86+
public void updateStatus(final SolutionVideoStatus status) {
87+
this.videoStatus = status;
88+
}
89+
90+
public boolean hasFailed() {
91+
return this.videoStatus.equals(SolutionVideoStatus.FAILED);
92+
}
93+
94+
public void updateVideoUrl(final String videoUrl) {
95+
solutionDetail.updateVideoUrl(videoUrl);
96+
}
7697
}

src/main/java/com/first/flash/climbing/solution/domain/dto/SolutionCreateRequestDto.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,23 @@
66
import jakarta.validation.constraints.NotNull;
77
import jakarta.validation.constraints.Size;
88
import java.time.LocalDate;
9+
import org.springframework.web.multipart.MultipartFile;
910

1011
public record SolutionCreateRequestDto(
12+
MultipartFile solutionVideo,
1113
@NotEmpty(message = "썸네일 URL은 필수입니다.") String thumbnailImageUrl,
12-
@NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl,
1314
@Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review,
1415
@NotNull(message = "풀이 일자 정보는 필수입니다.") LocalDate solvedDate,
1516
@ValidEnum(enumClass = PerceivedDifficulty.class) PerceivedDifficulty perceivedDifficulty) {
1617

17-
public SolutionCreateRequestDto(final String thumbnailImageUrl, final String videoUrl,
18-
final String review, final LocalDate solvedDate, final PerceivedDifficulty perceivedDifficulty) {
18+
public SolutionCreateRequestDto(final MultipartFile solutionVideo,
19+
final String thumbnailImageUrl, final String review, final LocalDate solvedDate,
20+
final PerceivedDifficulty perceivedDifficulty) {
21+
this.solutionVideo = solutionVideo;
1922
this.thumbnailImageUrl = thumbnailImageUrl;
20-
this.videoUrl = videoUrl;
2123
this.review = review;
2224
this.solvedDate = solvedDate;
23-
this.perceivedDifficulty = perceivedDifficulty != null ? perceivedDifficulty : PerceivedDifficulty.NORMAL;
25+
this.perceivedDifficulty =
26+
perceivedDifficulty != null ? perceivedDifficulty : PerceivedDifficulty.NORMAL;
2427
}
2528
}

src/main/java/com/first/flash/climbing/solution/domain/vo/SolutionDetail.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,8 @@ public static SolutionDetail of(final String review, final String thumbnailImage
3737
final LocalDate solvedDate, final PerceivedDifficulty perceivedDifficulty) {
3838
return new SolutionDetail(review, thumbnailImageUrl, videoUrl, solvedDate, perceivedDifficulty);
3939
}
40+
41+
public void updateVideoUrl(final String videoUrl) {
42+
this.videoUrl = videoUrl;
43+
}
4044
}

0 commit comments

Comments
 (0)