diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepository.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepository.java index 4dde6ece..4329afe8 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepository.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepository.java @@ -1,6 +1,7 @@ package shop.kkeujeok.kkeujeokbackend.dashboard.domain.repository; import java.util.List; +import java.util.Set; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import shop.kkeujeok.kkeujeokbackend.dashboard.personal.domain.PersonalDashboard; @@ -11,7 +12,7 @@ public interface DashboardCustomRepository { List findForPersonalDashboard(Member member); - List findForPersonalDashboardByCategory(Member member); + Set findCategoriesForDashboard(Member member); Page findForTeamDashboard(Member member, Pageable pageable); diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepositoryImpl.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepositoryImpl.java index 448f887a..83a9f615 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepositoryImpl.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/domain/repository/DashboardCustomRepositoryImpl.java @@ -7,6 +7,8 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -38,15 +40,15 @@ public List findForPersonalDashboard(Member member) { .fetch(); } - @Override - public List findForPersonalDashboardByCategory(Member member) { + public Set findCategoriesForDashboard(Member member) { return queryFactory .select(personalDashboard.category) .from(personalDashboard) - .where(personalDashboard._super.member.eq(member)) + .where(personalDashboard._super.member.eq(member) + .and(personalDashboard._super.status.eq(Status.ACTIVE))) .stream() - .toList(); + .collect(Collectors.toSet()); } @Override diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/exception/UnauthorizedAccessException.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/exception/UnauthorizedAccessException.java new file mode 100644 index 00000000..715f7def --- /dev/null +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/exception/UnauthorizedAccessException.java @@ -0,0 +1,13 @@ +package shop.kkeujeok.kkeujeokbackend.dashboard.exception; + +import shop.kkeujeok.kkeujeokbackend.global.error.exception.AccessDeniedGroupException; + +public class UnauthorizedAccessException extends AccessDeniedGroupException { + public UnauthorizedAccessException(String message) { + super(message); + } + + public UnauthorizedAccessException() { + this("대시보드에 접근할 수 있는 권한이 없습니다"); + } +} diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardController.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardController.java index 3b1538a6..befd6950 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardController.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardController.java @@ -58,11 +58,10 @@ public RspTemplate findById(@CurrentUserEmail Strin } @GetMapping("/categories") - public RspTemplate findForPersonalDashboardByCategories( - @CurrentUserEmail String email) { + public RspTemplate findCategoriesForDashboard(@CurrentUserEmail String email) { return new RspTemplate<>(HttpStatus.OK, "개인 대시보드 카테고리 조회", - personalDashboardService.findForPersonalDashboardByCategories(email)); + personalDashboardService.findCategoriesForDashboard(email)); } @DeleteMapping("/{dashboardId}") diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/dto/response/PersonalDashboardCategoriesResDto.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/dto/response/PersonalDashboardCategoriesResDto.java index 9b83a821..bbf8451c 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/dto/response/PersonalDashboardCategoriesResDto.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/dto/response/PersonalDashboardCategoriesResDto.java @@ -1,13 +1,14 @@ package shop.kkeujeok.kkeujeokbackend.dashboard.personal.api.dto.response; import java.util.List; +import java.util.Set; import lombok.Builder; @Builder public record PersonalDashboardCategoriesResDto( - List categories + Set categories ) { - public static PersonalDashboardCategoriesResDto from(List categories) { + public static PersonalDashboardCategoriesResDto from(Set categories) { return PersonalDashboardCategoriesResDto.builder() .categories(categories) .build(); diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardService.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardService.java index 9138aeed..a3e643ae 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardService.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardService.java @@ -1,10 +1,12 @@ package shop.kkeujeok.kkeujeokbackend.dashboard.personal.application; import java.util.List; +import java.util.Set; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import shop.kkeujeok.kkeujeokbackend.dashboard.exception.DashboardNotFoundException; +import shop.kkeujeok.kkeujeokbackend.dashboard.exception.UnauthorizedAccessException; import shop.kkeujeok.kkeujeokbackend.dashboard.personal.api.dto.request.PersonalDashboardSaveReqDto; import shop.kkeujeok.kkeujeokbackend.dashboard.personal.api.dto.request.PersonalDashboardUpdateReqDto; import shop.kkeujeok.kkeujeokbackend.dashboard.personal.api.dto.response.PersonalDashboardCategoriesResDto; @@ -73,16 +75,24 @@ public PersonalDashboardInfoResDto findById(String email, Long dashboardId) { PersonalDashboard dashboard = personalDashboardRepository.findById(dashboardId) .orElseThrow(DashboardNotFoundException::new); + validateDashboardAccess(dashboard, member); + double blockProgress = personalDashboardRepository.calculateCompletionPercentage(dashboard.getId()); return PersonalDashboardInfoResDto.detailOf(member, dashboard, blockProgress); } + private void validateDashboardAccess(PersonalDashboard dashboard, Member member) { + if (!dashboard.getMember().equals(member)) { + throw new UnauthorizedAccessException(); + } + } + // 개인 대시보드 카테고리 조회 - public PersonalDashboardCategoriesResDto findForPersonalDashboardByCategories(String email) { + public PersonalDashboardCategoriesResDto findCategoriesForDashboard(String email) { Member member = memberRepository.findByEmail(email).orElseThrow(MemberNotFoundException::new); - List categories = personalDashboardRepository.findForPersonalDashboardByCategory(member); + Set categories = personalDashboardRepository.findCategoriesForDashboard(member); return PersonalDashboardCategoriesResDto.from(categories); } diff --git a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/team/application/TeamDashboardService.java b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/team/application/TeamDashboardService.java index 4fa48a2e..78f26ba7 100644 --- a/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/team/application/TeamDashboardService.java +++ b/src/main/java/shop/kkeujeok/kkeujeokbackend/dashboard/team/application/TeamDashboardService.java @@ -8,6 +8,8 @@ import org.springframework.transaction.annotation.Transactional; import shop.kkeujeok.kkeujeokbackend.dashboard.exception.DashboardNotFoundException; import shop.kkeujeok.kkeujeokbackend.dashboard.exception.InvalidMemberInviteException; +import shop.kkeujeok.kkeujeokbackend.dashboard.exception.UnauthorizedAccessException; +import shop.kkeujeok.kkeujeokbackend.dashboard.personal.domain.PersonalDashboard; import shop.kkeujeok.kkeujeokbackend.dashboard.personal.exception.DashboardAccessDeniedException; import shop.kkeujeok.kkeujeokbackend.dashboard.team.api.dto.request.TeamDashboardSaveReqDto; import shop.kkeujeok.kkeujeokbackend.dashboard.team.api.dto.request.TeamDashboardUpdateReqDto; @@ -92,15 +94,26 @@ public TeamDashboardListResDto findForTeamDashboard(String email) { // 팀 대시보드 상세 조회 public TeamDashboardInfoResDto findById(String email, Long dashboardId) { - Member member = memberRepository.findByEmail(email).orElseThrow(MemberNotFoundException::new); + Member member = memberRepository.findByEmail("email").orElseThrow(MemberNotFoundException::new); TeamDashboard dashboard = teamDashboardRepository.findById(dashboardId) .orElseThrow(DashboardNotFoundException::new); + validateDashboardAccess(dashboard, member); + double blockProgress = teamDashboardRepository.calculateCompletionPercentage(dashboard.getId()); return TeamDashboardInfoResDto.detailOf(member, dashboard, blockProgress); } + private void validateDashboardAccess(TeamDashboard dashboard, Member member) { + boolean isMemberInDashboard = dashboard.getTeamDashboardMemberMappings().stream() + .anyMatch(mapping -> mapping.getMember().equals(member)); + + if (!dashboard.getMember().equals(member) && !isMemberInDashboard) { + throw new UnauthorizedAccessException(); + } + } + // 팀 대시보드 삭제 유무 업데이트 (논리 삭제) @Transactional public void delete(String email, Long dashboardId) { diff --git a/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardControllerTest.java b/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardControllerTest.java index 3c2695c7..1c78eaba 100644 --- a/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardControllerTest.java +++ b/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/api/PersonalDashboardControllerTest.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; +import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -268,9 +269,9 @@ void setUp(RestDocumentationContextProvider restDocumentation) { @Test void 개인_대시보드_카테고리_조회() throws Exception { // given - PersonalDashboardCategoriesResDto response = PersonalDashboardCategoriesResDto.from(List.of("category")); + PersonalDashboardCategoriesResDto response = PersonalDashboardCategoriesResDto.from(Set.of("category")); - given(personalDashboardService.findForPersonalDashboardByCategories(anyString())).willReturn(response); + given(personalDashboardService.findCategoriesForDashboard(anyString())).willReturn(response); // when & then mockMvc.perform(get("/api/dashboards/personal/categories") diff --git a/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardServiceTest.java b/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardServiceTest.java index 6006f86a..aa1e3aa9 100644 --- a/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardServiceTest.java +++ b/src/test/java/shop/kkeujeok/kkeujeokbackend/dashboard/personal/application/PersonalDashboardServiceTest.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Optional; +import java.util.Set; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -207,16 +208,15 @@ void setUp() { @Test void 개인_대시보드_카테고리_조회() { // given - List categories = List.of("category"); - when(personalDashboardRepository.findForPersonalDashboardByCategory(any(Member.class))).thenReturn(categories); + Set categories = Set.of("category"); + when(personalDashboardRepository.findCategoriesForDashboard(any(Member.class))).thenReturn(categories); // when - PersonalDashboardCategoriesResDto result = personalDashboardService.findForPersonalDashboardByCategories( + PersonalDashboardCategoriesResDto result = personalDashboardService.findCategoriesForDashboard( member.getEmail()); // then assertThat(result.categories()).hasSize(1); - assertThat(result.categories().get(0)).isEqualTo("category"); } @DisplayName("삭제되었던 개인 대시보드를 복구합니다.")