Skip to content

Commit

Permalink
feat: 멤버 회원가입 시, 필수 약관 비즈니스 로직 추가
Browse files Browse the repository at this point in the history
* feat: 회원가입 약관 도메인 추가

* feat: 회원가입 약관 목록 조회 기능 추가

* refactor: 정보 입력 중 필수 약관에 동의하도록 리팩토링

* fix: 약관 사용여부 디폴트 값 false로 수정

* test: 회원가입 이후, 정보 입력 시 변경된 방법으로 인한 테스트 수정

* test: 필수 약관 Id Set을 변경 및 Fixture수정 및 추가

* test: 비즈니스 로직 변경으로 인한 테스트 코드 수정

* feat: 필수 약관 동의 시, 저장 비즈니스 로직 추가

* fix: 매개변수 명 수정

* fix: memberId 로 매개변수 변경

* test: test description 수정

* chore: TermService 임시로 exclude 추가
  • Loading branch information
YongsHub authored Oct 20, 2023
1 parent 50c82e8 commit dd33cf9
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 12 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ jacocoTestCoverageVerification {
'com.ssafy.ssafsound.domain.auth.util.**',
'com.ssafy.ssafsound.domain.auth.service.token.**',
'com.ssafy.ssafsound.domain.QBaseTimeEntity',
'com.ssafy.ssafsound.domain.chat.service.*Service']
'com.ssafy.ssafsound.domain.chat.service.*Service',
'com.ssafy.ssafsound.domain.term.service.*Service']
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public EnvelopeResponse<GetMemberResDto> registerMemberInformation(
@Authentication AuthenticatedMember authenticatedMember,
@Valid @RequestBody PostMemberInfoReqDto postMemberInfoReqDto) {
return EnvelopeResponse.<GetMemberResDto>builder()
.data(memberService.registerMemberInformation(authenticatedMember, postMemberInfoReqDto))
.data(memberService.registerMemberInformation(authenticatedMember.getMemberId(), postMemberInfoReqDto))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;

@Builder
@AllArgsConstructor
Expand All @@ -31,6 +33,9 @@ public class PostMemberInfoReqDto {

private String campus;

@Builder.Default
private Set<Long> termIds = new HashSet<>();

@JsonIgnore
public boolean isNotSemesterPresent() {
return this.semester == null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public enum MemberErrorInfo {
SEMESTER_NOT_FOUND("713", "SSAFY Member 등록 또는 기수 수정 시, 기수 값은 필수입니다."),
MEMBER_PROFILE_SECRET("714", "멤버의 프로필 공개 여부를 확인하세요"),
MEMBER_NOT_SSAFY("715", "싸피생이 아닙니다."),
MEMBER_DELETED("716", "탈퇴한 회원입니다.");
MEMBER_DELETED("716", "탈퇴한 회원입니다."),
MEMBER_INPUT_INFORMATION_FAIL("717", "약관에 동의하셔야 합니다.");

private final String code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
import com.ssafy.ssafsound.domain.meta.domain.MetaData;
import com.ssafy.ssafsound.domain.meta.domain.MetaDataType;
import com.ssafy.ssafsound.domain.meta.service.MetaDataConsumer;
import com.ssafy.ssafsound.domain.term.domain.MemberTermAgreement;
import com.ssafy.ssafsound.domain.term.domain.Term;
import com.ssafy.ssafsound.domain.term.repository.MemberTermAgreementRepository;
import com.ssafy.ssafsound.domain.term.repository.TermRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
Expand All @@ -31,6 +35,7 @@
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@Service
@RequiredArgsConstructor
Expand All @@ -42,6 +47,8 @@ public class MemberService {
private final MemberProfileRepository memberProfileRepository;
private final MemberSkillRepository memberSkillRepository;
private final MemberLinkRepository memberLinkRepository;
private final TermRepository termRepository;
private final MemberTermAgreementRepository memberTermAgreementRepository;
private final MetaDataConsumer metaDataConsumer;
private final MemberConstantProvider memberConstantProvider;
private final ApplicationEventPublisher applicationEventPublisher;
Expand Down Expand Up @@ -85,17 +92,18 @@ public Member saveTokenByMember(

@Transactional
public GetMemberResDto registerMemberInformation(
AuthenticatedMember authenticatedMember,
Long memberId,
PostMemberInfoReqDto postMemberInfoReqDto) {
boolean existNickname = memberRepository.existsByNickname(postMemberInfoReqDto.getNickname());
Member member = memberRepository.findById(memberId)
.orElseThrow(() -> new MemberException(MemberErrorInfo.MEMBER_NOT_FOUND_BY_ID));

if(existNickname) {
throw new MemberException(MemberErrorInfo.MEMBER_NICKNAME_DUPLICATION);
} else if (isNotAgreedRequiredTerms(member, postMemberInfoReqDto.getTermIds())) {
throw new MemberException(MemberErrorInfo.MEMBER_INPUT_INFORMATION_FAIL);
}

Member member = memberRepository.findById(authenticatedMember.getMemberId())
.orElseThrow(() -> new MemberException(MemberErrorInfo.MEMBER_NOT_FOUND_BY_ID));

return member.registerMemberInformation(postMemberInfoReqDto, metaDataConsumer);
}

Expand Down Expand Up @@ -352,4 +360,20 @@ private void createMemberToken(
.build();
memberTokenRepository.save(memberToken);
}

private boolean isNotAgreedRequiredTerms(Member member, Set<Long> termIds) {
List<Term> terms = termRepository.getRequiredTerms();
boolean allIdsExistInTermSequences = terms.stream()
.map(Term::getId)
.allMatch(termIds::contains);

if (terms.size() != termIds.size()) {
return true;
} else if (!allIdsExistInTermSequences) {
return true;
} else {
memberTermAgreementRepository.saveAll(MemberTermAgreement.ofMemberAndTerms(member, terms));
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.ssafy.ssafsound.domain.term.controller;

import com.ssafy.ssafsound.domain.term.dto.GetTermsResDto;
import com.ssafy.ssafsound.domain.term.service.TermService;
import com.ssafy.ssafsound.global.common.response.EnvelopeResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/terms")
@RequiredArgsConstructor
public class TermController {

private final TermService termService;

@GetMapping
public EnvelopeResponse<GetTermsResDto> getTerms() {
return EnvelopeResponse.<GetTermsResDto>builder()
.data(termService.getTerms())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.ssafy.ssafsound.domain.term.domain;

import com.ssafy.ssafsound.domain.BaseTimeEntity;
import com.ssafy.ssafsound.domain.member.domain.Member;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.util.List;
import java.util.stream.Collectors;

@Entity(name = "member_term_agreement")
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MemberTermAgreement extends BaseTimeEntity {

@Id
@Column(name = "member_term_agreement_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "term_id")
private Term term;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;

public static List<MemberTermAgreement> ofMemberAndTerms(Member member, List<Term> terms) {
return terms.stream()
.map(term -> MemberTermAgreement.builder().member(member).term(term).build())
.collect(Collectors.toList());
}
}
44 changes: 44 additions & 0 deletions src/main/java/com/ssafy/ssafsound/domain/term/domain/Term.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.ssafy.ssafsound.domain.term.domain;

import com.ssafy.ssafsound.domain.BaseTimeEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;


@Entity(name="term")
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Term extends BaseTimeEntity {

@Id
@Column(name = "term_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String content;

@Column
private String name;

@Column
@Builder.Default
private Boolean usedYN = false;

@Column
@Builder.Default
private Boolean requiredYN = false;

@Column
private Integer sequence;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.ssafy.ssafsound.domain.term.domain;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TermElement {

private Long termId;

private String termName;

private String content;

private Boolean requiredYN;

private Integer sequence;

public static TermElement from(Term term) {
return TermElement.builder()
.termId(term.getId())
.termName(term.getName())
.content(term.getContent())
.requiredYN(term.getRequiredYN())
.sequence(term.getSequence())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ssafy.ssafsound.domain.term.dto;

import com.ssafy.ssafsound.domain.term.domain.TermElement;
import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
public class GetTermsResDto {
List<TermElement> termElements;

public static GetTermsResDto fromTermElements(List<TermElement> termElements) {
return GetTermsResDto.builder()
.termElements(termElements)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ssafy.ssafsound.domain.term.repository;

import com.ssafy.ssafsound.domain.term.domain.MemberTermAgreement;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberTermAgreementRepository extends JpaRepository<MemberTermAgreement, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.ssafy.ssafsound.domain.term.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssafy.ssafsound.domain.term.domain.Term;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

import static com.ssafy.ssafsound.domain.term.domain.QTerm.term;

@Repository
@RequiredArgsConstructor
public class TermRepository {

private final JPAQueryFactory jpaQueryFactory;

public List<Term> getTerms() {
return jpaQueryFactory
.selectFrom(term)
.where(term.usedYN.eq(true))
.orderBy(term.sequence.asc())
.fetch();

}

public List<Term> getRequiredTerms() {
return jpaQueryFactory
.selectFrom(term)
.where(term.usedYN.eq(true), term.requiredYN.eq(true))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.ssafy.ssafsound.domain.term.service;

import com.ssafy.ssafsound.domain.term.domain.TermElement;
import com.ssafy.ssafsound.domain.term.dto.GetTermsResDto;
import com.ssafy.ssafsound.domain.term.repository.TermRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TermService {

private final TermRepository termRepository;

@Transactional(readOnly = true)
public GetTermsResDto getTerms() {
return GetTermsResDto.fromTermElements(termRepository
.getTerms().stream()
.map(TermElement::from)
.collect(Collectors.toList()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
import org.springframework.restdocs.payload.RequestFieldsSnippet;
import org.springframework.restdocs.payload.ResponseFieldsSnippet;

import java.util.HashSet;
import java.util.Set;

import static com.ssafy.ssafsound.global.docs.snippet.CookieDescriptionSnippet.requestCookieAccessTokenMandatory;
import static com.ssafy.ssafsound.global.docs.snippet.CookieDescriptionSnippet.requestCookieAccessTokenNeedless;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -52,7 +55,8 @@ public RequestFieldsSnippet requestSSAFYSnippet() {
fieldWithPath("ssafyMember").description("싸피인 여부"),
fieldWithPath("isMajor").description("전공자 여부"),
fieldWithPath("semester").optional().description("싸피 기수"),
fieldWithPath("campus").optional().description("캠퍼스 이름")
fieldWithPath("campus").optional().description("캠퍼스 이름"),
fieldWithPath("termIds").description("필수 약관 동의 아이디 값")
);
}

Expand Down Expand Up @@ -160,6 +164,7 @@ void putMemberInformation() {
.nickname("james")
.ssafyMember(false)
.isMajor(true)
.termIds(new HashSet<>(Set.of(1L, 2L, 3L)))
.build();

restDocs
Expand Down
Loading

0 comments on commit dd33cf9

Please sign in to comment.