Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…l-up into feat/#272
  • Loading branch information
brgndyy committed Aug 16, 2024
2 parents 8190934 + e2a024f commit c13acad
Show file tree
Hide file tree
Showing 76 changed files with 2,342 additions and 260 deletions.
8 changes: 8 additions & 0 deletions backend/src/main/java/develup/api/MissionApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public ResponseEntity<ApiResponse<List<MissionResponse>>> getMissions() {
return ResponseEntity.ok(new ApiResponse<>(responses));
}

@GetMapping("/missions/in-progress")
@Operation(summary = "사용자가 시작한 미션 목록 조회 API", description = "사용자가 시작한 미션 목록을 조회합니다.")
public ResponseEntity<ApiResponse<List<MissionResponse>>> getInProgressMissions(@Auth Accessor accessor) {
List<MissionResponse> responses = missionService.getInProgressMissions(accessor.id());

return ResponseEntity.ok(new ApiResponse<>(responses));
}

@GetMapping("/missions/{missionId}")
@Operation(
summary = "미션 조회 API",
Expand Down
21 changes: 15 additions & 6 deletions backend/src/main/java/develup/api/SolutionApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import develup.api.auth.Auth;
import develup.api.common.ApiResponse;
import develup.application.auth.Accessor;
import develup.application.solution.MySolutionResponse;
import develup.application.solution.SolutionResponse;
import develup.application.solution.SolutionService;
import develup.application.solution.StartSolutionRequest;
import develup.application.solution.SubmitSolutionRequest;
import develup.domain.solution.SolutionSummary;
import develup.application.solution.SummarizedSolutionResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -53,17 +54,25 @@ public ResponseEntity<ApiResponse<SolutionResponse>> submitSolution(

@GetMapping("/solutions")
@Operation(summary = "솔루션 조회 목록 API", description = "솔루션 목록을 조회합니다.")
public ResponseEntity<ApiResponse<List<SolutionSummary>>> getSolutions() {
List<SolutionSummary> summaries = solutionService.getCompletedSummaries();
public ResponseEntity<ApiResponse<List<SummarizedSolutionResponse>>> getSolutions() {
List<SummarizedSolutionResponse> responses = solutionService.getCompletedSummaries();

return ResponseEntity.ok(new ApiResponse<>(summaries));
return ResponseEntity.ok(new ApiResponse<>(responses));
}

@GetMapping("/solutions/{id}")
@Operation(summary = "솔루션 조회 API", description = "솔루션을 조회합니다.")
public ResponseEntity<ApiResponse<SolutionResponse>> getSolution(@PathVariable Long id) {
SolutionResponse solutionResponse = solutionService.getById(id);
SolutionResponse response = solutionService.getById(id);

return ResponseEntity.ok(new ApiResponse<>(solutionResponse));
return ResponseEntity.ok(new ApiResponse<>(response));
}

@GetMapping("/solutions/mine")
@Operation(summary = "나의 솔루션 목록 조회 API", description = "내가 제출한 솔루션 목록을 조회합니다.")
public ResponseEntity<ApiResponse<List<MySolutionResponse>>> getMySolutions(@Auth Accessor accessor) {
List<MySolutionResponse> response = solutionService.getSubmittedSolutionsByMemberId(accessor.id());

return ResponseEntity.ok(new ApiResponse<>(response));
}
}
67 changes: 67 additions & 0 deletions backend/src/main/java/develup/api/SolutionCommentApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package develup.api;

import java.net.URI;
import java.util.List;
import develup.api.auth.Auth;
import develup.api.common.ApiResponse;
import develup.application.auth.Accessor;
import develup.application.solution.comment.CreateSolutionCommentResponse;
import develup.application.solution.comment.SolutionCommentRequest;
import develup.application.solution.comment.SolutionCommentService;
import develup.application.solution.comment.SolutionCommentRepliesResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Tag(name = "솔루션 댓글 API")
public class SolutionCommentApi {

private final SolutionCommentService solutionCommentService;

public SolutionCommentApi(SolutionCommentService solutionCommentService) {
this.solutionCommentService = solutionCommentService;
}

@GetMapping("/solutions/{solutionId}/comments")
@Operation(summary = "솔루션 댓글 조회 API", description = "솔루션의 댓글 목록을 조회합니다. 댓글들과 댓글들에 대한 답글을 조회합니다.")
public ResponseEntity<ApiResponse<List<SolutionCommentRepliesResponse>>> getComments(
@PathVariable Long solutionId
) {
List<SolutionCommentRepliesResponse> responses = solutionCommentService.getCommentsWithReplies(solutionId);

return ResponseEntity.ok(new ApiResponse<>(responses));
}

@PostMapping("/solutions/{solutionId}/comments")
@Operation(summary = "솔루션 댓글 추가 API", description = "솔루션에 댓글을 추가합니다. 부모 댓글 식별자로 답글을 추가할 수 있습니다.")
public ResponseEntity<ApiResponse<CreateSolutionCommentResponse>> addComment(
@PathVariable Long solutionId,
@Valid @RequestBody SolutionCommentRequest request,
@Auth Accessor accessor
) {
CreateSolutionCommentResponse response = solutionCommentService.addComment(solutionId, request, accessor.id());

URI location = URI.create("/solutions/" + response.solutionId() + "/comments/" + response.id());

return ResponseEntity.created(location).body(new ApiResponse<>(response));
}

@DeleteMapping("/solutions/comments/{commentId}")
@Operation(summary = "솔루션 댓글 삭제 API", description = "솔루션의 댓글을 삭제합니다.")
public ResponseEntity<Void> deleteComment(
@PathVariable Long commentId,
@Auth Accessor accessor
) {
solutionCommentService.deleteComment(commentId, accessor.id());

return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ public enum ExceptionType {
SOLUTION_ALREADY_SUBMITTED(HttpStatus.BAD_REQUEST, "이미 제출한 미션입니다."),
INVALID_URL(HttpStatus.BAD_REQUEST, "올바르지 않은 주소입니다."),
INVALID_TITLE(HttpStatus.BAD_REQUEST, "올바르지 않은 제목입니다."),
COMMENT_ALREADY_DELETED(HttpStatus.BAD_REQUEST, "이미 삭제된 댓글입니다."),
CANNOT_REPLY_TO_REPLY(HttpStatus.BAD_REQUEST, "답글에는 답글을 작성할 수 없습니다."),
COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 댓글입니다."),
COMMENT_NOT_WRITTEN_BY_MEMBER(HttpStatus.FORBIDDEN, "작성자만 댓글을 삭제할 수 있습니다."),
DUPLICATED_HASHTAG(HttpStatus.BAD_REQUEST, "중복된 해시태그입니다."),

;

private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public record OAuthUserInfo(
String name
) {

public OAuthUserInfo {
if (name == null || name.isBlank()) {
name = login;
}
}

public Member toMember(Provider provider) {
return new Member(
email,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package develup.application.hashtag;

import develup.domain.hashtag.HashTag;

public record HashTagResponse(Long id, String name) {

public static HashTagResponse from(HashTag hashTag) {
return new HashTagResponse(
hashTag.getId(),
hashTag.getName()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
package develup.application.mission;

import java.util.List;
import develup.application.hashtag.HashTagResponse;
import develup.domain.mission.Mission;
import develup.domain.mission.MissionHashTag;

public record MissionResponse(
Long id,
String title,
String thumbnail,
String summary,
String url
String url,
List<HashTagResponse> hashTags
) {

public static MissionResponse from(Mission mission) {
List<HashTagResponse> hashTagResponses = mission.getHashTags()
.stream()
.map(MissionHashTag::getHashTag)
.map(HashTagResponse::from)
.toList();

return new MissionResponse(
mission.getId(),
mission.getTitle(),
mission.getThumbnail(),
mission.getSummary(),
mission.getUrl()
mission.getUrl(),
hashTagResponses
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
import develup.application.auth.Accessor;
import develup.domain.mission.Mission;
import develup.domain.mission.MissionRepository;
import develup.domain.solution.Solution;
import develup.domain.solution.SolutionRepository;
import develup.domain.solution.SolutionStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
public class MissionService {

private final MissionRepository missionRepository;
Expand All @@ -22,13 +25,22 @@ public MissionService(MissionRepository missionRepository, SolutionRepository so
}

public List<MissionResponse> getMissions() {
return missionRepository.findAll().stream()
return missionRepository.findAllHashTaggedMission().stream()
.map(MissionResponse::from)
.toList();
}

public List<MissionResponse> getInProgressMissions(Long memberId) {
return solutionRepository.findAllByMember_IdAndStatus(memberId, SolutionStatus.IN_PROGRESS)
.stream()
.map(Solution::getMission)
.distinct()
.map(MissionResponse::from)
.toList();
}

public MissionWithStartedResponse getMission(Accessor accessor, Long missionId) {
Mission mission = missionRepository.findById(missionId)
Mission mission = missionRepository.findHashTaggedMissionById(missionId)
.orElseThrow(() -> new DevelupException(ExceptionType.MISSION_NOT_FOUND));

if (accessor.isGuest()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
package develup.application.mission;

import java.util.List;
import develup.application.hashtag.HashTagResponse;
import develup.domain.mission.Mission;
import develup.domain.mission.MissionHashTag;

public record MissionWithStartedResponse(
Long id,
String title,
String descriptionUrl,
String thumbnail,
String url,
boolean isStarted
boolean isStarted,
List<HashTagResponse> hashTags
) {

public static MissionWithStartedResponse of(Mission mission, boolean isStarted) {
List<HashTagResponse> hashTagResponses = mission.getHashTags()
.stream()
.map(MissionHashTag::getHashTag)
.map(HashTagResponse::from)
.toList();

return new MissionWithStartedResponse(
mission.getId(),
mission.getTitle(),
mission.getDescriptionUrl(),
mission.getThumbnail(),
mission.getUrl(),
isStarted
isStarted,
hashTagResponses
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package develup.application.solution;

import develup.domain.solution.Solution;

public record MySolutionResponse(Long id, String thumbnail, String title) {

public static MySolutionResponse from(Solution solution) {
return new MySolutionResponse(solution.getId(), solution.getMissionThumbnail(), solution.getTitle());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import develup.domain.solution.SolutionRepository;
import develup.domain.solution.SolutionStatus;
import develup.domain.solution.SolutionSubmit;
import develup.domain.solution.SolutionSummary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -104,7 +103,16 @@ public SolutionResponse getById(Long id) {
return SolutionResponse.from(solution);
}

public List<SolutionSummary> getCompletedSummaries() {
return solutionRepository.findCompletedSummaries();
public List<SummarizedSolutionResponse> getCompletedSummaries() {
return solutionRepository.findAllCompletedSolution().stream()
.map(SummarizedSolutionResponse::from)
.toList();
}

public List<MySolutionResponse> getSubmittedSolutionsByMemberId(Long memberId) {
List<Solution> mySolutions = solutionRepository.findAllByMember_IdAndStatus(memberId, SolutionStatus.COMPLETED);
return mySolutions.stream()
.map(MySolutionResponse::from)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package develup.application.solution;

import java.util.List;
import develup.application.hashtag.HashTagResponse;
import develup.domain.mission.MissionHashTag;
import develup.domain.solution.Solution;

public record SummarizedSolutionResponse(
Long id,
String title,
String thumbnail,
String description,
List<HashTagResponse> hashTags
) {

public static SummarizedSolutionResponse from(Solution solution) {
List<HashTagResponse> hashTagResponses = solution.getHashTags().stream()
.map(MissionHashTag::getHashTag)
.map(HashTagResponse::from)
.toList();

return new SummarizedSolutionResponse(
solution.getId(),
solution.getTitle(),
solution.getMissionThumbnail(),
solution.getDescription(),
hashTagResponses
);
}
}
Loading

0 comments on commit c13acad

Please sign in to comment.