Skip to content

Commit

Permalink
feat: MemberPart 삭제 기능 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
Cyma-s committed Oct 10, 2023
1 parent 93eda60 commit 5d42f7f
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ private HandlerInterceptor tokenInterceptor() {
.includePathPattern("/voting-songs/*/parts", PathMethod.POST)
.includePathPattern("/songs/*/parts/*/comments", PathMethod.POST)
.includePathPattern("/songs/*/member-parts", PathMethod.POST)
.includePathPattern("/member-parts/*", PathMethod.DELETE)
.includePathPattern("/members/*", PathMethod.DELETE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import shook.shook.auth.exception.OAuthException;
import shook.shook.auth.exception.TokenException;
import shook.shook.member.exception.MemberException;
import shook.shook.my_part.exception.MemberPartException;
import shook.shook.part.exception.PartException;
import shook.shook.song.exception.SongException;
import shook.shook.song.exception.killingpart.KillingPartCommentException;
Expand Down Expand Up @@ -55,7 +56,8 @@ public ResponseEntity<ErrorResponse> handleTokenException(final CustomException
MemberException.class,
VotingSongException.class,
VotingSongPartException.PartNotExistException.class,
PartException.class
PartException.class,
MemberPartException.class
})
public ResponseEntity<ErrorResponse> handleGlobalBadRequestException(final CustomException e) {
log.error(e.getErrorInfoLog());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shook.shook.auth.exception.AuthorizationException;
import shook.shook.member.domain.Member;
import shook.shook.member.domain.repository.MemberRepository;
import shook.shook.member.exception.MemberException;
Expand Down Expand Up @@ -44,4 +45,14 @@ private Song getSong(final Long songId) {
Map.of("songId", String.valueOf(songId))
));
}

@Transactional
public void delete(final Long memberId, final Long memberPartId) {
final MemberPart memberPart = memberPartRepository.findByMemberIdAndId(memberId, memberPartId)
.orElseThrow(() -> new AuthorizationException.UnauthenticatedException(
Map.of("memberId", String.valueOf(memberId), "memberPartId", String.valueOf(memberPartId))
));

memberPartRepository.delete(memberPart);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package shook.shook.my_part.domain.repository;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import shook.shook.my_part.domain.MemberPart;

public interface MemberPartRepository extends JpaRepository<MemberPart, Long> {

Optional<MemberPart> findByMemberIdAndId(final Long memberId, final Long memberPartId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -16,13 +17,13 @@
import shook.shook.my_part.ui.openapi.MemberPartApi;

@RequiredArgsConstructor
@RequestMapping("/songs/{song_id}/member-parts")
@RequestMapping
@RestController
public class MemberPartController implements MemberPartApi {

private final MemberPartService memberPartService;

@PostMapping
@PostMapping("/songs/{song_id}/member-parts")
public ResponseEntity<Void> register(
@PathVariable(name = "song_id") final Long songId,
@Authenticated final MemberInfo memberInfo,
Expand All @@ -32,4 +33,14 @@ public ResponseEntity<Void> register(

return ResponseEntity.status(HttpStatus.CREATED).build();
}

@DeleteMapping("/member-parts/{member_part_id}")
public ResponseEntity<Void> delete(
@PathVariable(name = "member_part_id") final Long memberPartId,
@Authenticated final MemberInfo memberInfo
) {
memberPartService.delete(memberInfo.getMemberId(), memberPartId);

return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.jdbc.Sql;
import shook.shook.auth.exception.AuthorizationException;
import shook.shook.member.domain.Member;
import shook.shook.member.domain.repository.MemberRepository;
import shook.shook.member.exception.MemberException;
import shook.shook.my_part.application.dto.MemberPartRegisterRequest;
import shook.shook.my_part.domain.MemberPart;
import shook.shook.my_part.domain.repository.MemberPartRepository;
import shook.shook.song.domain.Song;
import shook.shook.song.domain.repository.SongRepository;
import shook.shook.song.exception.SongException;
import shook.shook.support.UsingJpaTest;
Expand All @@ -34,7 +38,7 @@ void setUp() {
memberPartService = new MemberPartService(songRepository, memberRepository, memberPartRepository);
}

@DisplayName("존재하지 않는 노래에 멤버 파트를 등록하면 예외가 발생한다")
@DisplayName("존재하지 않는 노래에 멤버 파트를 등록하면 예외가 발생한다.")
@Test
void register_failNotExistSong() {
// given
Expand All @@ -47,7 +51,7 @@ void register_failNotExistSong() {
.isInstanceOf(SongException.SongNotExistException.class);
}

@DisplayName("존재하지 않는 멤버로 멤버 파트를 등록하면 예외가 발생한다")
@DisplayName("존재하지 않는 멤버로 멤버 파트를 등록하면 예외가 발생한다.")
@Test
void register_failNotExist() {
// given
Expand All @@ -59,4 +63,19 @@ void register_failNotExist() {
assertThatThrownBy(() -> memberPartService.register(1L, notExistMemberId, request))
.isInstanceOf(MemberException.MemberNotExistException.class);
}

@DisplayName("존재하지 않는 멤버로 멤버 파트를 삭제하면 예외가 발생한다.")
@Test
void delete_failUnauthenticatedMember() {
// given
final Song song = songRepository.findById(1L).get();
final Member member = memberRepository.findById(1L).get();
final MemberPart memberPart = memberPartRepository.save(MemberPart.forSave(20, 10, song, member));
final Long notExistMemberId = 0L;

// when
// then
assertThatThrownBy(() -> memberPartService.delete(notExistMemberId, memberPart.getId()))
.isInstanceOf(AuthorizationException.UnauthenticatedException.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
Expand All @@ -13,7 +15,11 @@
import org.springframework.http.HttpStatus;
import org.springframework.test.context.jdbc.Sql;
import shook.shook.auth.application.TokenProvider;
import shook.shook.member.domain.Member;
import shook.shook.member.domain.repository.MemberRepository;
import shook.shook.my_part.application.dto.MemberPartRegisterRequest;
import shook.shook.my_part.domain.MemberPart;
import shook.shook.my_part.domain.repository.MemberPartRepository;
import shook.shook.song.domain.Song;
import shook.shook.song.domain.repository.SongRepository;

Expand All @@ -35,13 +41,20 @@ void setUp() {
@Autowired
private SongRepository songRepository;

@Autowired
private MemberPartRepository memberPartRepository;

@Autowired
private MemberRepository memberRepository;

@DisplayName("멤버의 파트를 등록 성공 시 201 상태 코드를 반환한다.")
@Test
void registerMemberPart() {
// given
final Song song = songRepository.findById(1L).get();
final Member member = memberRepository.findById(1L).get();
final MemberPartRegisterRequest request = new MemberPartRegisterRequest(5, 10);
final String accessToken = tokenProvider.createAccessToken(1L, "nickname");
final String accessToken = tokenProvider.createAccessToken(member.getId(), member.getNickname());

// when
// then
Expand All @@ -52,4 +65,60 @@ void registerMemberPart() {
.when().log().all().post("/songs/{songId}/member-parts", song.getId())
.then().statusCode(HttpStatus.CREATED.value());
}

@DisplayName("잘못된 정보로 파트를 등록 시 400 상태 코드를 반환한다.")
@CsvSource({"-1, 10", "190, 15", "5, 25"})
@ParameterizedTest
void register_failBadRequest(final int startSecond, final int length) {
// given
final Song song = songRepository.findById(1L).get();
final Member member = memberRepository.findById(1L).get();
final MemberPartRegisterRequest request = new MemberPartRegisterRequest(startSecond, length);
final String accessToken = tokenProvider.createAccessToken(member.getId(), member.getNickname());

// when
// then
RestAssured.given().log().all()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.body(request)
.contentType(ContentType.JSON)
.when().log().all().post("/songs/{songId}/member-parts", song.getId())
.then().statusCode(HttpStatus.BAD_REQUEST.value());
}

@DisplayName("멤버 파트 삭제 성공 시 204 상태 코드를 반환한다.")
@Test
void delete() {
// given
final Song song = songRepository.findById(1L).get();
final Member member = memberRepository.findById(1L).get();
final String accessToken = tokenProvider.createAccessToken(member.getId(), member.getNickname());
final MemberPart memberPart = memberPartRepository.save(MemberPart.forSave(5, 10, song, member));

// when
// then
RestAssured.given().log().all()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.when().log().all().delete("/member-parts/{memberPartId}", memberPart.getId())
.then().statusCode(HttpStatus.NO_CONTENT.value());
}

@DisplayName("자신의 파트가 아닌 파트를 삭제하려고 시도할 시 403 상태 코드를 반환한다.")
@Test
void delete_failUnauthorizedMember() {
// given
final Song song = songRepository.findById(1L).get();
final Member member = memberRepository.findById(1L).get();
final MemberPart memberPart = memberPartRepository.save(MemberPart.forSave(5, 10, song, member));
final Member otherMember = memberRepository.save(new Member("[email protected]", "nickname"));
final String otherMemberAccessToken = tokenProvider.createAccessToken(otherMember.getId(),
otherMember.getNickname());

// when
// then
RestAssured.given().log().all()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + otherMemberAccessToken)
.when().log().all().delete("/member-parts/{memberPartId}", memberPart.getId())
.then().statusCode(HttpStatus.FORBIDDEN.value());
}
}

0 comments on commit 5d42f7f

Please sign in to comment.