Skip to content

Commit

Permalink
Merge pull request #47 from SWM-Flash/feature/FLASH-214-user-upload-api
Browse files Browse the repository at this point in the history
업로드 API 수정
  • Loading branch information
wonyangs authored Aug 30, 2024
2 parents f383174 + 208d1e2 commit bd8d966
Show file tree
Hide file tree
Showing 22 changed files with 317 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.first.flash.account.member.application.dto.MemberCompleteRegistrationResponse;
import com.first.flash.account.member.application.dto.MemberInfoResponse;
import com.first.flash.account.member.domain.Member;
import com.first.flash.account.member.domain.MemberInfoUpdatedEvent;
import com.first.flash.account.member.domain.MemberDeletedEvent;
import com.first.flash.account.member.domain.MemberRepository;
import com.first.flash.account.member.exception.exceptions.MemberNotFoundException;
Expand Down Expand Up @@ -44,6 +45,10 @@ public MemberCompleteRegistrationResponse completeMemberRegistration(
}
member.completeRegistration(request.nickName(), request.instagramId(), request.height(),
request.gender(), request.reach(), request.profileImageUrl());

Events.raise(MemberInfoUpdatedEvent.of(member.getId(), member.getNickName(),
member.getInstagramId()));

return MemberCompleteRegistrationResponse.toDto(member);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.first.flash.account.member.domain;

import com.first.flash.global.event.Event;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class MemberInfoUpdatedEvent extends Event {

private final UUID memberId;
private final String nickName;
private final String instagramId;

public static MemberInfoUpdatedEvent of(final UUID memberId, final String nickName,
final String instagramId) {
return new MemberInfoUpdatedEvent(memberId, nickName, instagramId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.first.flash.climbing.sector.domain.SectorExpiredEvent;
import com.first.flash.climbing.sector.domain.SectorInfoUpdatedEvent;
import com.first.flash.climbing.sector.domain.SectorRemovalDateUpdatedEvent;
import com.first.flash.climbing.solution.domain.SolutionDeletedEvent;
import com.first.flash.climbing.solution.domain.SolutionSavedEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
Expand Down Expand Up @@ -35,6 +36,12 @@ public void updateProblemSolutionInfo(final SolutionSavedEvent event) {
problemsService.updateProblemSolutionInfo(event.getProblemId());
}

@EventListener
@Transactional
public void updateProblemDeletedSolutionInfo(final SolutionDeletedEvent event) {
problemsService.updateProblemDeletedSolutionInfo(event.getProblemId());
}

@EventListener
@Transactional
public void updateQueryProblemInfo(final SectorInfoUpdatedEvent event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ public void updateProblemSolutionInfo(final UUID problemId) {
queryProblem.addSolutionCount();
}

@Transactional
public void updateProblemDeletedSolutionInfo(final UUID problemId) {
QueryProblem queryProblem = problemReadService.findQueryProblemById(problemId);
queryProblem.decrementSolutionCount();
}

@Transactional
public void updateQueryProblemInfo(final Long sectorId, final String sectorName,
final LocalDate settingDate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ public void addSolutionCount() {
calculateRecommendationValue();
}

public void decrementSolutionCount() {
solutionCount--;
if (solutionCount == 0) {
hasSolution = false;
}
calculateRecommendationValue();
}

private void enableSolution() {
if (!hasSolution) {
hasSolution = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.first.flash.climbing.solution.application;

import com.first.flash.account.member.domain.MemberInfoUpdatedEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
@RequiredArgsConstructor
public class SolutionEventHandler {

private final SolutionSaveService solutionSaveService;

@EventListener
@Transactional
public void updateSolutionInfo(final MemberInfoUpdatedEvent event) {
solutionSaveService.updateUploaderInfo(event.getMemberId(), event.getNickName(),
event.getInstagramId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.first.flash.climbing.solution.application;

import com.first.flash.account.member.application.MemberService;
import com.first.flash.account.member.domain.Member;
import com.first.flash.climbing.solution.application.dto.SolutionResponseDto;
import com.first.flash.climbing.solution.domain.Solution;
import com.first.flash.climbing.solution.domain.SolutionRepository;
import com.first.flash.climbing.solution.domain.SolutionSavedEvent;
import com.first.flash.climbing.solution.domain.dto.SolutionCreateRequestDto;
import com.first.flash.global.event.Events;
import com.first.flash.global.util.AuthUtil;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class SolutionSaveService {

private final MemberService memberService;
private final SolutionRepository solutionRepository;

@Transactional
public SolutionResponseDto saveSolution(final UUID problemId,
final SolutionCreateRequestDto createRequestDto) {
UUID id = AuthUtil.getId();
Member member = memberService.findById(id);

Solution solution = Solution.of(member.getNickName(), createRequestDto.review(),
member.getInstagramId(),
createRequestDto.videoUrl(), problemId, member.getId());
Solution savedSolution = solutionRepository.save(solution);
Events.raise(SolutionSavedEvent.of(savedSolution.getProblemId()));
return SolutionResponseDto.toDto(savedSolution);
}

@Transactional
public void updateUploaderInfo(final UUID uploaderId, final String nickName,
final String instagramId) {
solutionRepository.findAllByUploaderId(uploaderId)
.forEach(solution -> solution.updateUploaderInfo(nickName, instagramId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import com.first.flash.climbing.problem.domain.ProblemIdConfirmRequestedEvent;
import com.first.flash.climbing.solution.application.dto.SolutionMetaResponseDto;
import com.first.flash.climbing.solution.application.dto.SolutionResponseDto;
import com.first.flash.climbing.solution.application.dto.SolutionUpdateRequestDto;
import com.first.flash.climbing.solution.application.dto.SolutionsResponseDto;
import com.first.flash.climbing.solution.domain.Solution;
import com.first.flash.climbing.solution.domain.SolutionDeletedEvent;
import com.first.flash.climbing.solution.domain.SolutionRepository;
import com.first.flash.climbing.solution.domain.SolutionSavedEvent;
import com.first.flash.climbing.solution.domain.dto.SolutionCreateRequestDto;
import com.first.flash.climbing.solution.exception.exceptions.SolutionNotFoundException;
import com.first.flash.global.event.Events;
import java.util.List;
Expand All @@ -23,15 +23,6 @@ public class SolutionService {

private final SolutionRepository solutionRepository;

@Transactional
public SolutionResponseDto saveSolution(final UUID problemId,
final SolutionCreateRequestDto createRequestDto) {
Solution solution = Solution.of(createRequestDto, problemId);
Solution savedSolution = solutionRepository.save(solution);
Events.raise(SolutionSavedEvent.of(savedSolution.getProblemId()));
return SolutionResponseDto.toDto(savedSolution);
}

public Solution findSolutionById(final Long id) {
return solutionRepository.findById(id)
.orElseThrow(() -> new SolutionNotFoundException(id));
Expand All @@ -47,4 +38,34 @@ public SolutionsResponseDto findAllSolutionsByProblemId(final UUID problemId) {

return new SolutionsResponseDto(solutions, new SolutionMetaResponseDto(solutions.size()));
}

public SolutionsResponseDto findAllSolutionsByMemberId(final UUID memberId) {
List<SolutionResponseDto> solutions = solutionRepository.findAllByUploaderId(memberId)
.stream()
.map(SolutionResponseDto::toDto)
.toList();

return new SolutionsResponseDto(solutions, new SolutionMetaResponseDto(solutions.size()));
}

@Transactional
public SolutionResponseDto updateContent(final Long id,
final SolutionUpdateRequestDto requestDto) {

Solution solution = solutionRepository.findById(id)
.orElseThrow(() -> new SolutionNotFoundException(id));
solution.updateContentInfo(requestDto.review(), requestDto.videoUrl());

return SolutionResponseDto.toDto(solution);
}

@Transactional
public void deleteSolution(final Long id, final UUID problemId) {
Events.raise(ProblemIdConfirmRequestedEvent.of(problemId));
solutionRepository.findById(id).orElseThrow(() -> new SolutionNotFoundException(id));

solutionRepository.deleteById(id);

Events.raise(SolutionDeletedEvent.of(problemId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

import com.first.flash.climbing.solution.domain.Solution;
import com.first.flash.climbing.solution.domain.vo.SolutionDetail;
import com.first.flash.climbing.solution.domain.vo.UploaderDetail;

public record SolutionResponseDto(Long id, String uploader, String review, String instagramId,
String videoUrl) {

public static SolutionResponseDto toDto(final Solution solution) {
SolutionDetail detail = solution.getSolutionDetail();
SolutionDetail solutionDetail = solution.getSolutionDetail();
UploaderDetail uploaderDetail = solution.getUploaderDetail();

return new SolutionResponseDto(solution.getId(), detail.getUploader(), detail.getReview(),
detail.getInstagramId(), detail.getVideoUrl());
return new SolutionResponseDto(solution.getId(), uploaderDetail.getUploader(),
solutionDetail.getReview(), uploaderDetail.getInstagramId(),
solutionDetail.getVideoUrl());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.first.flash.climbing.solution.application.dto;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;

public record SolutionUpdateRequestDto(
@NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl,
@Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review) {

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.first.flash.climbing.solution.domain;

import com.first.flash.climbing.solution.domain.dto.SolutionCreateRequestDto;
import com.first.flash.climbing.solution.domain.vo.SolutionDetail;
import com.first.flash.climbing.solution.domain.vo.UploaderDetail;
import com.first.flash.global.domain.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
Expand All @@ -16,30 +17,42 @@
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Solution {
public class Solution extends BaseEntity {

private static final Long DEFAULT_OPTIONAL_WEIGHT = 0L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
SolutionDetail solutionDetail;
private Long optionalWeight;
@Column(columnDefinition = "BINARY(16)")
private UUID problemId;
private SolutionDetail solutionDetail;
private UploaderDetail uploaderDetail;
private Long optionalWeight;

protected Solution(final String uploader, final String review, final String instagramId,
final String videoUrl, final UUID problemId) {
final String videoUrl, final UUID problemId, final UUID uploaderId) {

this.solutionDetail = SolutionDetail.of(uploader, review, instagramId, videoUrl);
this.solutionDetail = SolutionDetail.of(review, videoUrl);
this.uploaderDetail = UploaderDetail.of(uploaderId, uploader, instagramId);
this.optionalWeight = DEFAULT_OPTIONAL_WEIGHT;
this.problemId = problemId;
}

public static Solution of(final SolutionCreateRequestDto createRequestDto,
final UUID problemId) {
public static Solution of(final String uploader, final String review, final String instagramId,
final String videoUrl,
final UUID problemId, final UUID uploaderId) {

return new Solution(uploader, review, instagramId, videoUrl, problemId, uploaderId);
}

public void updateUploaderInfo(final String uploader, final String instagramId) {
UUID uploaderId = this.uploaderDetail.getUploaderId();

this.uploaderDetail = UploaderDetail.of(uploaderId, uploader, instagramId);
}

return new Solution(createRequestDto.uploader(), createRequestDto.review(),
createRequestDto.instagramId(), createRequestDto.videoUrl(), problemId);
public void updateContentInfo(final String review, final String videoUrl) {
this.solutionDetail = SolutionDetail.of(review, videoUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.first.flash.climbing.solution.domain;

import com.first.flash.global.event.Event;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class SolutionDeletedEvent extends Event {

private UUID problemId;

public static SolutionDeletedEvent of(final UUID problemId) {
return new SolutionDeletedEvent(problemId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ public interface SolutionRepository {
Optional<Solution> findById(final Long id);

List<Solution> findAllByProblemId(final UUID problemId);

List<Solution> findAllByUploaderId(final UUID uploaderId);

void deleteById(final Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

public record SolutionCreateRequestDto(
@NotEmpty(message = "비디오 URL은 필수입니다.") String videoUrl,
@NotEmpty(message = "업로더 정보는 필수입니다.") String uploader,
@Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review,
String instagramId) {
@Size(max = 500, message = "리뷰는 최대 500자까지 가능합니다.") String review) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,15 @@
@Getter
public class SolutionDetail {

private String uploader;
private String review;
private String instagramId;
private String videoUrl;

protected SolutionDetail(final String uploader, final String review, final String instagramId,
final String videoUrl) {

this.uploader = uploader;
protected SolutionDetail(final String review, final String videoUrl) {
this.review = review;
this.instagramId = instagramId;
this.videoUrl = videoUrl;
}

public static SolutionDetail of(final String uploader, final String review,
final String instagramId, final String videoUrl) {

return new SolutionDetail(uploader, review, instagramId, videoUrl);
public static SolutionDetail of(final String review, final String videoUrl) {
return new SolutionDetail(review, videoUrl);
}
}
Loading

0 comments on commit bd8d966

Please sign in to comment.