Skip to content

Commit

Permalink
feat: 템플릿 추천 로직 구현 (#73)
Browse files Browse the repository at this point in the history
* feat: 추천템플릿 조회 및 설정 API 컨트롤러 로직 개발

* feat: 추천을 위한 enum 정의

* feat: 추천템플릿 조회 및 설정 API 서비스 로직 개발
  • Loading branch information
mikekks authored Aug 2, 2024
1 parent 356edd4 commit 7f7caf8
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
package org.layer.domain.form.controller;

import org.layer.common.annotation.MemberId;
import org.layer.domain.form.controller.dto.request.RecommendFormQueryDto;
import org.layer.domain.form.controller.dto.request.RecommendFormSetRequest;
import org.layer.domain.form.controller.dto.response.DefaultFormGetResponse;
import org.layer.domain.form.controller.dto.response.RecommendFormResponseDto;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;

@Tag(name = "회고 폼(커스텀 템플릿)", description = "회고 폼 관련 API")
public interface FormApi {

@Operation(summary = "회고 폼(커스텀 템플릿) 조회 (기본 회고폼 포함)", method = "GET", description = "회고 폼(커스텀 템플릿)을 조회하는 기능입니다.")
ResponseEntity<DefaultFormGetResponse> getForm(@PathVariable Long formId, @MemberId Long memberId);

@Parameters(
{
@Parameter(name = "periodic", description = "회고 주기적 여부", example = "true", required = true),
@Parameter(name = "period", description = "회고 주기", example = "WEEKLY"),
@Parameter(name = "purpose", description = "회고 목적", example = "TEAM_GROWTH", required = true)
}
)
@Operation(summary = "추천 템플릿 조회", method = "GET", description = "추천 템플릿을 조회하는 기능입니다.")
ResponseEntity<RecommendFormResponseDto> getRecommendTemplate(@ModelAttribute @Valid @Parameter(hidden = true) RecommendFormQueryDto queryDto,
@MemberId Long memberId);

@Operation(summary = "추천 템플릿 설정", method = "POST", description = "추천 템플릿을 설정하는 기능입니다.")
ResponseEntity<Void> setRecommendTemplate(@RequestBody @Valid RecommendFormSetRequest request, @MemberId Long memberId);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package org.layer.domain.form.controller;

import org.layer.common.annotation.MemberId;
import org.layer.domain.form.controller.dto.request.RecommendFormQueryDto;
import org.layer.domain.form.controller.dto.request.RecommendFormSetRequest;
import org.layer.domain.form.controller.dto.response.DefaultFormGetResponse;
import org.layer.domain.form.controller.dto.response.RecommendFormResponseDto;
import org.layer.domain.form.service.FormService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

@RestController
Expand All @@ -25,4 +32,23 @@ public ResponseEntity<DefaultFormGetResponse> getForm(@PathVariable Long formId,
return ResponseEntity.ok().body(dto);
}

@Override
@GetMapping("/recommend")
public ResponseEntity<RecommendFormResponseDto> getRecommendTemplate(
@Valid @ModelAttribute RecommendFormQueryDto queryDto,
@MemberId Long memberId) {

RecommendFormResponseDto response = formService.getRecommendTemplate(queryDto, memberId);
return ResponseEntity.ok().body(response);
}

@Override
@PostMapping("/recommend")
public ResponseEntity<Void> setRecommendTemplate(@RequestBody @Valid RecommendFormSetRequest request,
@MemberId Long memberId) {

formService.setRecommendTemplate(request, memberId);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.layer.domain.form.controller.dto.request;

import org.layer.domain.form.enums.RetrospectPeriod;
import org.layer.domain.form.enums.RetrospectPurpose;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

@Schema(name = "RecommendFormQueryDto", description = "회고 템플릿 요청 queryParam")
public record RecommendFormQueryDto(
@NotNull
@Schema(description = "회고 주기적 여부", example = "true")
boolean periodic,
@Schema(description = "회고가 주기적일 때, 구체적인 주기", example = "WEEKLY")
RetrospectPeriod period,
@NotNull
@Schema(description = "회고 목적", example = "TEAM_GROWTH")
RetrospectPurpose purpose
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.layer.domain.form.controller.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

@Schema(name = "RecommendFormSetRequest", description = "추천 템플릿 설정 요청 Dto")
public record RecommendFormSetRequest(
@NotNull
@Schema(description = "추천 템플릿 폼 id", example = "3")
Long formId,
@NotNull
@Schema(description = "스페이스 id", example = "1")
Long spaceId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.layer.domain.form.controller.dto.response;

import java.util.List;

import org.layer.domain.form.entity.Form;
import org.layer.domain.tag.entity.Tag;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(name = "RecommendFormResponseDto", description = "회고 템플릿 응답 Dto")
public record RecommendFormResponseDto(
@Schema(description = "추천 템플릿 id \n 1. 추천템플릿 설정 API에 해당 데이터 사용 \n 2. 자세한 내용 확인하는 API 사용할 때 해당 데이터 사용", example = "3")
Long formId,
@Schema(description = "템플릿(폼) 이름", example = "차근차근, 단계적인 회고")
String formName,
@Schema(description = "태그", example = "[\"KPT\", \"태그2\"]")
List<String> tags,
@Schema(description = "템플릿(폼) 이미지 url", example = "[url 형식]")
String formImageUrl

) {
public static RecommendFormResponseDto of(Form form, List<Tag> tags){

List<String> tagNames = tags.stream()
.map(Tag::getTagName)
.toList();

return new RecommendFormResponseDto(form.getId(), form.getTitle(), tagNames, null);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package org.layer.domain.form.service;

import java.util.List;
import java.util.Random;

import org.layer.domain.form.controller.dto.request.RecommendFormQueryDto;
import org.layer.domain.form.controller.dto.request.RecommendFormSetRequest;
import org.layer.domain.form.controller.dto.response.DefaultFormGetResponse;
import org.layer.domain.form.controller.dto.response.DefaultQuestionGetResponse;
import org.layer.domain.form.controller.dto.response.RecommendFormResponseDto;
import org.layer.domain.form.entity.Form;
import org.layer.domain.form.repository.FormRepository;
import org.layer.domain.question.entity.Question;
import org.layer.domain.question.repository.QuestionRepository;
import org.layer.domain.space.entity.Space;
import org.layer.domain.space.entity.Team;
import org.layer.domain.space.repository.MemberSpaceRelationRepository;
import org.layer.domain.space.repository.SpaceRepository;
import org.layer.domain.tag.entity.Tag;
import org.layer.domain.tag.repository.TagRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -21,9 +29,14 @@
public class FormService {
private final FormRepository formRepository;
private final MemberSpaceRelationRepository memberSpaceRelationRepository;
private final SpaceRepository spaceRepository;
private final QuestionRepository questionRepository;
private final TagRepository tagRepository;

public DefaultFormGetResponse getForm(Long formId, Long memberId){
private static final int MIN = 10000;
private static final int MAX = 10002;

public DefaultFormGetResponse getForm(Long formId, Long memberId) {
Form form = formRepository.findByIdOrThrow(formId);

// 해당 스페이스 팀원인지 검증
Expand All @@ -40,4 +53,29 @@ public DefaultFormGetResponse getForm(Long formId, Long memberId){
return DefaultFormGetResponse.of(form.getTitle(), questionResponses);
}

public RecommendFormResponseDto getRecommendTemplate(RecommendFormQueryDto queryDto, Long memberId) {
Random random = new Random();
Long formId = random.nextLong(MAX - MIN + 1) + MIN;

Form form = formRepository.findByIdOrThrow(formId);

List<Tag> tags = tagRepository.findAllByFormId(form.getId());

// TODO: 템플릿 이미지 필요

return RecommendFormResponseDto.of(form, tags);
}

@Transactional
public void setRecommendTemplate(RecommendFormSetRequest request, Long memberId) {
// 팀 소속 여부 검증 로직
Team team = new Team(memberSpaceRelationRepository.findAllBySpaceId(request.spaceId()));
team.validateTeamMembership(memberId);

Form form = formRepository.findByIdOrThrow(request.formId());

Space space = spaceRepository.findByIdOrThrow(request.spaceId());
space.updateFormId(form.getId(), memberId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public class Form extends BaseEntity {
/*
* 해당 폼 생성한 멤버 id
*/
@NotNull
private Long memberId;

private Long spaceId;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.layer.domain.form.enums;

public enum RetrospectPeriod {
WEEKLY, MONTHLY, QUARTERLY, END_PROJECT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.layer.domain.form.enums;

public enum RetrospectPurpose {
CHECK_PROGRESS, PERSONAL_GROWTH, TEAM_GROWTH, IMPROVE_COMMUNICATION, SHARE_EXPERIENCE, IMPROVE_PROBLEM, SHARE_EMOTION, STRATEGY_SETTING
}
30 changes: 30 additions & 0 deletions layer-domain/src/main/java/org/layer/domain/tag/entity/Tag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.layer.domain.tag.entity;

import org.layer.domain.common.BaseTimeEntity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Tag extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String tagName;

private Long formId;

private Long retrospectId;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.layer.domain.tag.repository;


import java.util.List;

import org.layer.domain.tag.entity.Tag;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TagRepository extends JpaRepository<Tag, Long> {
List<Tag> findAllByFormId(Long formId);
}

0 comments on commit 7f7caf8

Please sign in to comment.