Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
 into feat/#432
  • Loading branch information
chosim-dvlpr committed Sep 19, 2024
2 parents 99dc21e + 61fb443 commit 658267d
Show file tree
Hide file tree
Showing 17 changed files with 400 additions and 18 deletions.
8 changes: 8 additions & 0 deletions backend/src/main/java/develup/api/DiscussionApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,12 @@ public ResponseEntity<ApiResponse<DiscussionResponse>> createDiscussion(

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

@GetMapping("/discussions/mine")
@Operation(summary = "나의 디스커션 목록 조회 API", description = "내가 작성한 디스커션 목록을 조회합니다.")
public ResponseEntity<ApiResponse<List<SummarizedDiscussionResponse>>> getMyDiscussions(@Auth Accessor accessor) {
List<SummarizedDiscussionResponse> response = discussionService.getDiscussionsByMemberId(accessor.id());

return ResponseEntity.ok(new ApiResponse<>(response));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,15 @@ public DiscussionResponse create(Long memberId, CreateDiscussionRequest request)
}

public List<SummarizedDiscussionResponse> getSummaries(String mission, String hashTagName) {
return discussionRepository.findByMissionAndHashTagName(mission, hashTagName).stream()
return discussionRepository.findAllByMissionAndHashTagName(mission, hashTagName).stream()
.map(SummarizedDiscussionResponse::from)
.toList();
}

public List<SummarizedDiscussionResponse> getDiscussionsByMemberId(Long memberId) {
List<Discussion> myDiscussions = discussionRepository.findAllByMember_Id(memberId);

return myDiscussions.stream()
.map(SummarizedDiscussionResponse::from)
.toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public interface DiscussionRepository extends JpaRepository<Discussion, Long> {
AND sht.name = :hashTag
))
""")
List<Discussion> findByMissionAndHashTagName(
List<Discussion> findAllByMissionAndHashTagName(
@Param("mission") String mission,
@Param("hashTag") String hashTagName
);
Expand All @@ -41,4 +41,15 @@ List<Discussion> findByMissionAndHashTagName(
WHERE d.id = :id
""")
Optional<Discussion> findFetchById(Long id);

@Query("""
SELECT d
FROM Discussion d
JOIN FETCH d.mission m
JOIN FETCH d.member me
JOIN FETCH d.discussionHashTags.hashTags dhts
JOIN FETCH dhts.hashTag ht
WHERE me.id = :memberId
""")
List<Discussion> findAllByMember_Id(Long memberId);
}
24 changes: 24 additions & 0 deletions backend/src/test/java/develup/api/DiscussionApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,30 @@ void getSolution() throws Exception {
.andExpect(jsonPath("$.data.mission.url", equalTo("https://github.com/develup-mission/java-smoking")));
}

@Test
@DisplayName("나의 디스커션 목록을 조회한다.")
void getMyDiscussions() throws Exception {
List<SummarizedDiscussionResponse> myDiscussions = List.of(
SummarizedDiscussionResponse.from(createDiscussion()),
SummarizedDiscussionResponse.from(createDiscussion())
);

BDDMockito.given(discussionService.getDiscussionsByMemberId(any()))
.willReturn(myDiscussions);

mockMvc.perform(get("/discussions/mine"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.data[0].id", equalTo(1)))
.andExpect(jsonPath("$.data[0].title", equalTo("루터회관 흡연단속 구현에 대한 고찰")))
.andExpect(jsonPath("$.data[0].mission", equalTo("루터회관 흡연단속")))
.andExpect(jsonPath("$.data[0].hashTags[0].id", equalTo(1)))
.andExpect(jsonPath("$.data[0].hashTags[0].name", equalTo("JAVA")))
.andExpect(jsonPath("$.data[0].member.id", equalTo(1)))
.andExpect(jsonPath("$.data[0].member.name", equalTo("tester")))
.andExpect(jsonPath("$.data[0].commentCount", equalTo(100)));
}

private Discussion createDiscussion() {
HashTag hashTag = HashTagTestData.defaultHashTag()
.withId(1L)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,24 @@ void getById() {
.hasMessage("존재하지 않는 디스커션입니다.");
}

@Test
@DisplayName("나의 디스커션 리스트를 조회한다.")
@Transactional
void getDiscussionsByMemberId() {
Member member = memberRepository.save(MemberTestData.defaultMember().withId(1L).build());
Mission mission = missionRepository.save(MissionTestData.defaultMission().build());
HashTag hashTag = hashTagRepository.save(HashTagTestData.defaultHashTag().build());
Discussion discussion = DiscussionTestData.defaultDiscussion()
.withMember(member)
.withMission(mission)
.withHashTags(List.of(hashTag))
.build();

discussionRepository.save(discussion);

assertThat(discussionService.getDiscussionsByMemberId(member.getId())).hasSize(1);
}

private void createDiscussion(Mission mission, HashTag hashTag) {
Member member = memberRepository.save(MemberTestData.defaultMember().build());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package develup.domain.discussion;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

import java.util.List;
import java.util.function.Function;
Expand Down Expand Up @@ -44,7 +45,7 @@ void findAllDiscussion() {
createDiscussion(mission, hashTag);
createDiscussion(mission, hashTag);

List<Discussion> actual = discussionRepository.findByMissionAndHashTagName(
List<Discussion> actual = discussionRepository.findAllByMissionAndHashTagName(
"all",
"all"
);
Expand All @@ -62,7 +63,7 @@ void findAllDiscussionByHashTag() {
createDiscussion(mission, hashTag1);
createDiscussion(mission, hashTag2);

List<Discussion> discussions = discussionRepository.findByMissionAndHashTagName(
List<Discussion> discussions = discussionRepository.findAllByMissionAndHashTagName(
"all",
"JAVA"
);
Expand All @@ -84,7 +85,7 @@ void findAllDiscussionByMission() {
createDiscussion(mission1, hashTag);
createDiscussion(mission2, hashTag);

List<Discussion> discussions = discussionRepository.findByMissionAndHashTagName(
List<Discussion> discussions = discussionRepository.findAllByMissionAndHashTagName(
"루터회관 흡연단속",
"all"
);
Expand Down Expand Up @@ -113,6 +114,38 @@ void findFetchById() {
.hasValue(savedDiscussion.getId());
}

@Test
@DisplayName("멤버 식별자를 통해 디스커션을 조회한다.")
@Transactional
void findByMember_Id() {
Member member1 = memberRepository.save(MemberTestData.defaultMember().withId(1L).build());
Member member2 = memberRepository.save(MemberTestData.defaultMember().withId(2L).build());
Mission mission = missionRepository.save(MissionTestData.defaultMission().build());
HashTag hashTag = hashTagRepository.save(HashTagTestData.defaultHashTag().build());

Discussion discussionByMember1 = DiscussionTestData.defaultDiscussion()
.withMission(mission)
.withMember(member1)
.withHashTags(List.of(hashTag))
.build();
Discussion discussionByMember2 = DiscussionTestData.defaultDiscussion()
.withMission(mission)
.withMember(member2)
.withHashTags(List.of(hashTag))
.build();

discussionRepository.save(discussionByMember1);
discussionRepository.save(discussionByMember2);

List<Discussion> discussionsByMember1 = discussionRepository.findAllByMember_Id(member1.getId());
List<Discussion> discussionsByMember2 = discussionRepository.findAllByMember_Id(member2.getId());

assertAll(
() -> assertThat(discussionsByMember1).hasSize(1),
() -> assertThat(discussionsByMember2).hasSize(1)
);
}

private void createDiscussion(Mission mission, HashTag hashTag) {
Member member = memberRepository.save(MemberTestData.defaultMember().build());

Expand Down
63 changes: 63 additions & 0 deletions frontend/src/components/DiscussionList/DiscussionList.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import styled from 'styled-components';
import CommentCount from '@/assets/images/comment-count.svg';

export const DiscussionListContainer = styled.div`
display: flex;
flex-direction: column;
gap: 2.5rem;
`;

export const DiscussionItemContainer = styled.div`
background-color: ${(props) => props.theme.colors.white};
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.4rem 3.4rem;
box-sizing: border-box;
box-shadow: ${(props) => props.theme.boxShadow.shadow04};
border-radius: 2.8rem;
`;

export const BadgeWrapper = styled.div`
display: flex;
gap: 0.7rem;
`;

export const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
gap: 0.5rem;
`;

export const Title = styled.p`
color: ${(props) => props.theme.colors.black};
${(props) => props.theme.font.body}
`;

export const WriterImg = styled.img`
border-radius: 100%;
max-width: 4.2rem;
max-height: 4.2rem;
`;

export const DiscussionRight = styled.div`
display: flex;
align-items: center;
gap: 1.7rem;
width: 10.5rem;
color: ${(props) => props.theme.colors.grey400};
${(props) => props.theme.font.caption};
`;

export const CommentWrapper = styled.div`
display: flex;
gap: 0.7rem;
`;

export const CommentCountIcon = styled(CommentCount)`
width: 1.4rem;
height: 1.4rem;
`;
34 changes: 34 additions & 0 deletions frontend/src/components/DiscussionList/DiscussionListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Discussion } from '@/types';
import * as S from './DiscussionList.styled';
import Badge from '../common/Badge';

export default function DiscussionListItem({
title,
mission,
hashTags,
member,
commentCount,
}: Omit<Discussion, 'id'>) {
return (
<S.DiscussionItemContainer>
<S.ContentWrapper>
<S.BadgeWrapper>
{/* TODO: Badge 색상 변경 필요 @프룬 */}
<Badge text={mission} />
{hashTags.map((hashTag) => (
<Badge key={hashTag.id} text={`# ${hashTag.name}`} />
))}
</S.BadgeWrapper>
<S.Title>{title}</S.Title>
</S.ContentWrapper>

<S.DiscussionRight>
<S.WriterImg src={member.imageUrl} />
<S.CommentWrapper>
<S.CommentCountIcon />
<p>{commentCount}</p>
</S.CommentWrapper>
</S.DiscussionRight>
</S.DiscussionItemContainer>
);
}
96 changes: 96 additions & 0 deletions frontend/src/components/DiscussionList/discussionsMock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[
{
"id": 1,
"title": "객체지향이 뭘까요?",
"content": "객체지향에 대해 토론해봅시다.",
"mission": {
"id": 1,
"title": "주문",
"thumbnail": "https://raw.githubusercontent.com/develup-mission/docs/main/image/java-order.png",
"summary": "배달 주문을 받아보자",
"url": "https://github.com/develup-mission/java-order",
"hashTags": [
{
"id": 1,
"name": "JAVA"
},
{
"id": 2,
"name": "객체지향"
},
{
"id": 3,
"name": "클린코드"
}
]
},
"member": {
"id": 1,
"email": "[email protected]",
"name": "구름",
"imageUrl": "https://avatars.githubusercontent.com/u/75781414?v=4"
},
"hashTags": [
{
"id": 1,
"name": "JAVA"
},
{
"id": 2,
"name": "객체지향"
},
{
"id": 3,
"name": "클린코드"
}
],
"commentCount": 0
},
{
"id": 2,
"title": "여기까지가 50글자 입니다. 여기까지가 50글자 입니다. 여기까지가 50글자 입니다. 하이",
"content": "객체지향에 대해 토론해봅시다.",
"mission": {
"id": 1,
"title": "주문",
"thumbnail": "https://raw.githubusercontent.com/develup-mission/docs/main/image/java-order.png",
"summary": "배달 주문을 받아보자",
"url": "https://github.com/develup-mission/java-order",
"hashTags": [
{
"id": 1,
"name": "JAVA"
},
{
"id": 2,
"name": "객체지향"
},
{
"id": 3,
"name": "클린코드"
}
]
},
"member": {
"id": 1,
"email": "[email protected]",
"name": "구름",
"imageUrl": "https://avatars.githubusercontent.com/u/75781414?v=4"
},
"hashTags": [
{
"id": 1,
"name": "JAVA"
},
{
"id": 2,
"name": "객체지향"
},
{
"id": 3,
"name": "클린코드"
}
],
"commentCount": 200
}
]
Loading

0 comments on commit 658267d

Please sign in to comment.