-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/#49 내 명함에서 활동을 추가 삭제하는 기능 #52
The head ref may contain hidden characters: "Feature/#49-\uB0B4_\uBA85\uD568\uC5D0\uC11C_\uD65C\uB3D9\uC744_\uCD94\uAC00_\uC0AD\uC81C\uD558\uB294_\uAE30\uB2A5"
Changes from all commits
7c336a6
9f6731e
8b8e36a
a997ffc
8485bb6
6330966
15ab790
0d98894
56fb089
aee6b17
cec893d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
= EMM-SALE API Docs | ||
:doctype: book | ||
:icons: font | ||
:source-highlighter: highlightjs | ||
:toc: left | ||
:toclevels: 2 | ||
:sectlinks: | ||
|
||
== Product | ||
|
@@ -87,3 +89,33 @@ include::{snippets}/wish-with-no-authentication-products/request-headers.adoc[] | |
|
||
.HTTP response | ||
include::{snippets}/wish-with-no-authentication-products/http-response.adoc[] | ||
|
||
== Career | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT : '커리어'라는 이름을 봤을 때 정확히 어떤 기능이 포함될지 예상하기 어려운 것 같아요(직관성이 떨어지는 것 같습니다) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 고유명사를 다같이 논의를 해봐야할 것 같네요. 월요일에 논의해봐요! |
||
=== `POST`: 커리어 등록 API | ||
|
||
.HTTP request 설명 | ||
include::{snippets}/add-career/request-fields.adoc[] | ||
|
||
.HTTP request | ||
include::{snippets}/add-career/http-request.adoc[] | ||
|
||
.HTTP response | ||
include::{snippets}/add-career/http-response.adoc[] | ||
|
||
.HTTP response 설명 | ||
include::{snippets}/add-career/response-fields.adoc[] | ||
|
||
|
||
=== `DELETE`: 커리어 삭제 API | ||
|
||
.HTTP request 설명 | ||
include::{snippets}/delete-career/request-fields.adoc[] | ||
|
||
.HTTP request | ||
include::{snippets}/delete-career/http-request.adoc[] | ||
|
||
.HTTP response | ||
include::{snippets}/delete-career/http-response.adoc[] | ||
|
||
.HTTP response 설명 | ||
include::{snippets}/delete-career/response-fields.adoc[] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,18 @@ | ||
package com.emmsale.member.application; | ||
|
||
import static java.util.stream.Collectors.toList; | ||
|
||
import com.emmsale.career.domain.CareerRepository; | ||
import com.emmsale.member.application.dto.MemberCareerAddRequest; | ||
import com.emmsale.member.application.dto.MemberCareerDeleteRequest; | ||
import com.emmsale.member.application.dto.MemberCareerInitialRequest; | ||
import com.emmsale.member.application.dto.MemberCareerResponse; | ||
import com.emmsale.member.domain.Member; | ||
import com.emmsale.member.domain.MemberCareer; | ||
import com.emmsale.member.domain.MemberCareerRepository; | ||
import com.emmsale.member.exception.MemberException; | ||
import com.emmsale.member.exception.MemberExceptionType; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
@@ -19,17 +25,61 @@ public class MemberCareerService { | |
private final MemberCareerRepository memberCareerRepository; | ||
private final CareerRepository careerRepository; | ||
|
||
public void registerCareer(final Member member, final MemberCareerInitialRequest memberCareerInitialRequest) { | ||
public void registerCareer( | ||
final Member member, | ||
final MemberCareerInitialRequest memberCareerInitialRequest | ||
) { | ||
final List<Long> careerIds = memberCareerInitialRequest.getCareerIds(); | ||
saveMemberCareers(member, careerIds); | ||
|
||
member.updateName(memberCareerInitialRequest.getName()); | ||
} | ||
|
||
private void saveMemberCareers(final Member member, final List<Long> careerIds) { | ||
final List<MemberCareer> memberCareers = careerRepository.findAllById(careerIds) | ||
.stream() | ||
.map(it -> new MemberCareer(it, member)) | ||
.collect(Collectors.toList()); | ||
.collect(toList()); | ||
|
||
member.updateName(memberCareerInitialRequest.getName()); | ||
validateAllCareerIdsExist(careerIds, memberCareers); | ||
|
||
memberCareerRepository.saveAll(memberCareers); | ||
} | ||
|
||
private void validateAllCareerIdsExist( | ||
final List<Long> careerIds, | ||
final List<MemberCareer> memberCareers | ||
) { | ||
if (memberCareers.size() != careerIds.size()) { | ||
throw new MemberException(MemberExceptionType.INVALID_CAREER_IDS); | ||
} | ||
} | ||
|
||
public List<MemberCareerResponse> addCareer( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 개인적인 코드 취향입니다!! public 메서드들 사이에 private 메서드가 껴있는게 저는 조금 어색하게 느껴집니다. 특히, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 진짜 취향인 것 같네요 .저는 굳이 public private 기준으로 분류할 필요는 없다고 생각하거든요. 위에서 아래로 읽었을 때 바로 인지할 수 있으면 된다고 생각해요. 코드 배치정도까지는 각자 편한 스타일로 작성하는건 어떨까요? |
||
final Member member, | ||
final MemberCareerAddRequest memberCareerAddRequest | ||
) { | ||
final List<Long> careerIds = memberCareerAddRequest.getCareerIds(); | ||
saveMemberCareers(member, careerIds); | ||
|
||
return MemberCareerResponse.from(memberCareerRepository.findAllByMember(member)); | ||
} | ||
|
||
public List<MemberCareerResponse> deleteCareer( | ||
final Member member, | ||
final MemberCareerDeleteRequest memberCareerDeleteRequest | ||
) { | ||
final List<Long> deleteCareerIds = memberCareerDeleteRequest.getCareerIds(); | ||
|
||
final List<Long> savedMemberCareerIds = | ||
memberCareerRepository.findAllByMemberAndCareerIds(member, deleteCareerIds) | ||
.stream() | ||
.map(MemberCareer::getId) | ||
.collect(toList()); | ||
|
||
memberCareerRepository.deleteAllByIdInBatch(savedMemberCareerIds); | ||
|
||
return MemberCareerResponse.from(memberCareerRepository.findAllByMember(member)); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.emmsale.member.application.dto; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class MemberActivityResponse { | ||
|
||
private final Long id; | ||
private final String name; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.emmsale.member.application.dto; | ||
|
||
import java.util.List; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class MemberCareerAddRequest { | ||
|
||
private final List<Long> careerIds; | ||
|
||
private MemberCareerAddRequest() { | ||
this(null); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.emmsale.member.application.dto; | ||
|
||
import java.util.List; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class MemberCareerDeleteRequest { | ||
|
||
private final List<Long> careerIds; | ||
|
||
private MemberCareerDeleteRequest() { | ||
this(null); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package com.emmsale.member.application.dto; | ||
|
||
import static java.util.Comparator.comparing; | ||
import static java.util.stream.Collectors.groupingBy; | ||
import static java.util.stream.Collectors.toList; | ||
|
||
import com.emmsale.career.domain.ActivityType; | ||
import com.emmsale.career.domain.Career; | ||
import com.emmsale.member.domain.MemberCareer; | ||
import java.util.ArrayList; | ||
import java.util.EnumMap; | ||
import java.util.List; | ||
import java.util.Map.Entry; | ||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public class MemberCareerResponse { | ||
|
||
private final String activityName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 말씀해주신 것처럼 activity career라는 용어는 인지하기 어려울 것 같아요. 심지어 이번에 직무도 빠졌으니까 조금 더 애매한 용어가 되버린 것 같네요. 고유명사에 대한 논의를 한 번 해보고 크게 리팩터링 해봐야할 것 같네요. |
||
private final List<MemberActivityResponse> memberActivityResponses; | ||
|
||
public static List<MemberCareerResponse> from(final List<MemberCareer> memberCareers) { | ||
final EnumMap<ActivityType, List<Career>> groupByActivityType = | ||
groupingByActivityTypeAndSortedByCareerName(memberCareers); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드가 아름답네요 b |
||
|
||
final List<MemberCareerResponse> responses = new ArrayList<>(); | ||
|
||
for (final Entry<ActivityType, List<Career>> entry : groupByActivityType.entrySet()) { | ||
final List<MemberActivityResponse> activityResponse = | ||
mapToMemberActivityResponses(entry); | ||
|
||
responses.add(new MemberCareerResponse(entry.getKey().getValue(), activityResponse)); | ||
} | ||
|
||
return responses; | ||
} | ||
|
||
private static List<MemberActivityResponse> mapToMemberActivityResponses( | ||
final Entry<ActivityType, List<Career>> entry | ||
) { | ||
return entry.getValue() | ||
.stream() | ||
.map(it -> new MemberActivityResponse(it.getId(), it.getName())) | ||
.collect(toList()); | ||
} | ||
|
||
private static EnumMap<ActivityType, List<Career>> groupingByActivityTypeAndSortedByCareerName( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
로직은 흠잡을 데 없는 것 같습니다👍👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗 이 피드백을 미쳐 못보고 머지해버렸네요. 추가로 하나 PR 파서 빠르게 수정하고 머지하도록 하겠습니다. |
||
final List<MemberCareer> memberCareers | ||
) { | ||
return memberCareers | ||
.stream() | ||
.map(MemberCareer::getCareer) | ||
.sorted(comparing(career -> career.getName().toLowerCase())) | ||
.collect( | ||
groupingBy(Career::getActivityType, () -> new EnumMap<>(ActivityType.class), toList()) | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,20 @@ | ||
package com.emmsale.member.domain; | ||
|
||
import java.util.List; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.repository.query.Param; | ||
|
||
public interface MemberCareerRepository extends JpaRepository<MemberCareer, Long> { | ||
|
||
@Query("select mc from MemberCareer mc where mc.member = :member") | ||
List<MemberCareer> findAllByMember(@Param("member") final Member member); | ||
|
||
@Query("select mc from MemberCareer mc " | ||
+ "where mc.member = :member " | ||
+ "and mc.career.id in :deleteCareerIds") | ||
List<MemberCareer> findAllByMemberAndCareerIds( | ||
@Param("member") final Member member, | ||
@Param("deleteCareerIds") final List<Long> deleteCareerIds | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Product는 이전 기획과 관련된 명세이니 지워도 괜찮을 것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RestDocs를 위한 예시 코드였어요. 삭제하도록 할게요!