Skip to content
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

refactor: 쿠폰 및 알림 Authorization Member 적용 리팩터링 #82

Merged
merged 3 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/main/java/com/moabam/api/application/coupon/CouponService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.api.domain.coupon.repository.CouponSearchRepository;
import com.moabam.api.domain.member.Role;
import com.moabam.api.dto.coupon.CouponResponse;
import com.moabam.api.dto.coupon.CouponSearchRequest;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.global.auth.model.AuthorizationMember;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;
Expand All @@ -28,16 +30,18 @@ public class CouponService {
private final CouponSearchRepository couponSearchRepository;

@Transactional
public void createCoupon(Long adminId, CreateCouponRequest request) {
public void createCoupon(AuthorizationMember admin, CreateCouponRequest request) {
validateAdminRole(admin);
validateConflictCouponName(request.name());
validateCouponPeriod(request.startAt(), request.endAt());

Coupon coupon = CouponMapper.toEntity(adminId, request);
Coupon coupon = CouponMapper.toEntity(admin.id(), request);
couponRepository.save(coupon);
}

@Transactional
public void deleteCoupon(Long adminId, Long couponId) {
public void deleteCoupon(AuthorizationMember admin, Long couponId) {
validateAdminRole(admin);
Coupon coupon = couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.NOT_FOUND_COUPON));
couponRepository.delete(coupon);
Expand All @@ -59,6 +63,12 @@ public List<CouponResponse> getCoupons(CouponSearchRequest request) {
.toList();
}

private void validateAdminRole(AuthorizationMember admin) {
if (!admin.role().equals(Role.ADMIN)) {
throw new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND);
}
}

private void validateConflictCouponName(String name) {
if (couponRepository.existsByName(name)) {
throw new ConflictException(ErrorMessage.CONFLICT_COUPON_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import com.moabam.api.domain.room.repository.ParticipantSearchRepository;
import com.moabam.api.dto.notification.KnockNotificationStatusResponse;
import com.moabam.api.infrastructure.redis.NotificationRepository;
import com.moabam.global.auth.annotation.MemberTest;
import com.moabam.global.auth.model.AuthorizationMember;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;
import com.moabam.global.error.model.ErrorMessage;
Expand All @@ -38,10 +38,10 @@ public class NotificationService {
private final ParticipantSearchRepository participantSearchRepository;

@Transactional
public void sendKnockNotification(MemberTest member, Long targetId, Long roomId) {
public void sendKnockNotification(AuthorizationMember member, Long targetId, Long roomId) {
roomService.validateRoomById(roomId);

String knockKey = generateKnockKey(member.memberId(), targetId, roomId);
String knockKey = generateKnockKey(member.id(), targetId, roomId);
validateConflictKnockNotification(knockKey);
validateFcmToken(targetId);

Expand All @@ -65,12 +65,12 @@ public void sendCertificationTimeNotification() {
/**
* TODO : 영명-재윤님 방 조회하실 때, 특정 사용자의 방 내 참여자들에 대한 콕 찌르기 여부를 반환해주는 메서드이니 사용하시기 바랍니다.
*/
public KnockNotificationStatusResponse checkMyKnockNotificationStatusInRoom(MemberTest member, Long roomId) {
List<Participant> participants = participantSearchRepository.findOtherParticipantsInRoom(member.memberId(),
roomId);
public KnockNotificationStatusResponse checkMyKnockNotificationStatusInRoom(AuthorizationMember member,
Long roomId) {
List<Participant> participants = participantSearchRepository.findOtherParticipantsInRoom(member.id(), roomId);

Predicate<Long> knockPredicate = targetId ->
notificationRepository.existsByKey(generateKnockKey(member.memberId(), targetId, roomId));
notificationRepository.existsByKey(generateKnockKey(member.id(), targetId, roomId));

Map<Boolean, List<Long>> knockNotificationStatus = participants.stream()
.map(Participant::getMemberId)
Expand Down
11 changes: 7 additions & 4 deletions src/main/java/com/moabam/api/presentation/CouponController.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.moabam.api.dto.coupon.CouponResponse;
import com.moabam.api.dto.coupon.CouponSearchRequest;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.global.auth.annotation.CurrentMember;
import com.moabam.global.auth.model.AuthorizationMember;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
Expand All @@ -27,14 +29,15 @@ public class CouponController {

@PostMapping("/admins/coupons")
@ResponseStatus(HttpStatus.CREATED)
public void createCoupon(@Valid @RequestBody CreateCouponRequest request) {
couponService.createCoupon(1L, request);
public void createCoupon(@CurrentMember AuthorizationMember admin,
@Valid @RequestBody CreateCouponRequest request) {
couponService.createCoupon(admin, request);
}

@DeleteMapping("/admins/coupons/{couponId}")
@ResponseStatus(HttpStatus.OK)
public void deleteCoupon(@PathVariable Long couponId) {
couponService.deleteCoupon(1L, couponId);
public void deleteCoupon(@CurrentMember AuthorizationMember admin, @PathVariable Long couponId) {
couponService.deleteCoupon(admin, couponId);
}

@GetMapping("/coupons/{couponId}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import org.springframework.web.bind.annotation.RestController;

import com.moabam.api.application.notification.NotificationService;
import com.moabam.global.auth.annotation.MemberTest;
import com.moabam.global.auth.annotation.CurrentMember;
import com.moabam.global.auth.model.AuthorizationMember;

import lombok.RequiredArgsConstructor;

Expand All @@ -18,7 +19,8 @@ public class NotificationController {
private final NotificationService notificationService;

@GetMapping("/rooms/{roomId}/members/{memberId}")
public void sendKnockNotification(@PathVariable Long roomId, @PathVariable Long memberId) {
notificationService.sendKnockNotification(new MemberTest(1L, "nickname"), memberId, roomId);
public void sendKnockNotification(@CurrentMember AuthorizationMember member, @PathVariable Long roomId,
@PathVariable Long memberId) {
notificationService.sendKnockNotification(member, memberId, roomId);
}
}

This file was deleted.

59 changes: 52 additions & 7 deletions src/test/java/com/moabam/api/application/CouponServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@
import com.moabam.api.domain.coupon.CouponType;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.api.domain.coupon.repository.CouponSearchRepository;
import com.moabam.api.domain.member.Role;
import com.moabam.api.dto.coupon.CouponResponse;
import com.moabam.api.dto.coupon.CouponSearchRequest;
import com.moabam.api.dto.coupon.CreateCouponRequest;
import com.moabam.global.auth.model.AuthorizationMember;
import com.moabam.global.auth.model.AuthorizationThreadLocal;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;
import com.moabam.global.error.model.ErrorMessage;
import com.moabam.support.annotation.WithMember;
import com.moabam.support.common.FilterProcessExtension;
import com.moabam.support.fixture.CouponFixture;

@ExtendWith(MockitoExtension.class)
@ExtendWith({MockitoExtension.class, FilterProcessExtension.class})
class CouponServiceTest {

@InjectMocks
Expand All @@ -42,86 +47,126 @@ class CouponServiceTest {
@Mock
private CouponSearchRepository couponSearchRepository;

@WithMember(role = Role.ADMIN)
@DisplayName("쿠폰을 성공적으로 발행한다. - Void")
@Test
void couponService_createCoupon() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
String couponType = CouponType.GOLDEN_COUPON.getTypeName();
CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2);

given(couponRepository.existsByName(any(String.class))).willReturn(false);

// When
couponService.createCoupon(1L, request);
couponService.createCoupon(admin, request);

// Then
verify(couponRepository).save(any(Coupon.class));
}

@WithMember(role = Role.USER)
@DisplayName("권한 없는 사용자가 쿠폰을 발행한다. - NotFoundException")
@Test
void couponService_createCoupon_Admin_NotFoundException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
String couponType = CouponType.GOLDEN_COUPON.getTypeName();
CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2);

// When & Then
assertThatThrownBy(() -> couponService.createCoupon(admin, request))
.isInstanceOf(NotFoundException.class)
.hasMessage(ErrorMessage.MEMBER_NOT_FOUND.getMessage());
}

@WithMember(role = Role.ADMIN)
@DisplayName("중복된 쿠폰명을 발행한다. - ConflictException")
@Test
void couponService_createCoupon_ConflictException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
String couponType = CouponType.GOLDEN_COUPON.getTypeName();
CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 1, 2);

given(couponRepository.existsByName(any(String.class))).willReturn(true);

// When & Then
assertThatThrownBy(() -> couponService.createCoupon(1L, request))
assertThatThrownBy(() -> couponService.createCoupon(admin, request))
.isInstanceOf(ConflictException.class)
.hasMessage(ErrorMessage.CONFLICT_COUPON_NAME.getMessage());
}

@WithMember(role = Role.ADMIN)
@DisplayName("존재하지 않는 쿠폰 종류를 발행한다. - NotFoundException")
@Test
void couponService_createCoupon_NotFoundException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
CreateCouponRequest request = CouponFixture.createCouponRequest("UNKNOWN", 1, 2);
given(couponRepository.existsByName(any(String.class))).willReturn(false);

// When & Then
assertThatThrownBy(() -> couponService.createCoupon(1L, request))
assertThatThrownBy(() -> couponService.createCoupon(admin, request))
.isInstanceOf(NotFoundException.class)
.hasMessage(ErrorMessage.NOT_FOUND_COUPON_TYPE.getMessage());
}

@WithMember(role = Role.ADMIN)
@DisplayName("쿠폰 발급 종료 기간이 시작 기간보다 더 이전인 쿠폰을 발행한다. - BadRequestException")
@Test
void couponService_createCoupon_BadRequestException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
String couponType = CouponType.GOLDEN_COUPON.getTypeName();
CreateCouponRequest request = CouponFixture.createCouponRequest(couponType, 2, 1);
given(couponRepository.existsByName(any(String.class))).willReturn(false);

// When & Then
assertThatThrownBy(() -> couponService.createCoupon(1L, request))
assertThatThrownBy(() -> couponService.createCoupon(admin, request))
.isInstanceOf(BadRequestException.class)
.hasMessage(ErrorMessage.INVALID_COUPON_PERIOD.getMessage());
}

@WithMember(role = Role.ADMIN)
@DisplayName("쿠폰 아이디와 일치하는 쿠폰을 삭제한다. - Void")
@Test
void couponService_deleteCoupon() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
Coupon coupon = CouponFixture.coupon(10, 100);
given(couponRepository.findById(any(Long.class))).willReturn(Optional.of(coupon));

// When
couponService.deleteCoupon(1L, 1L);
couponService.deleteCoupon(admin, 1L);

// Then
verify(couponRepository).delete(coupon);
}

@WithMember(role = Role.USER)
@DisplayName("권한 없는 사용자가 쿠폰을 삭제한다. - NotFoundException")
@Test
void couponService_deleteCoupon_Admin_NotFoundException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();

// When & Then
assertThatThrownBy(() -> couponService.deleteCoupon(admin, 1L))
.isInstanceOf(NotFoundException.class)
.hasMessage(ErrorMessage.MEMBER_NOT_FOUND.getMessage());
}

@WithMember(role = Role.ADMIN)
@DisplayName("존재하지 않는 쿠폰 아이디를 삭제하려고 시도한다. - NotFoundException")
@Test
void couponService_deleteCoupon_NotFoundException() {
// Given
AuthorizationMember admin = AuthorizationThreadLocal.getAuthorizationMember();
given(couponRepository.findById(any(Long.class))).willReturn(Optional.empty());

// When & Then
assertThatThrownBy(() -> couponService.deleteCoupon(1L, 1L))
assertThatThrownBy(() -> couponService.deleteCoupon(admin, 1L))
.isInstanceOf(NotFoundException.class)
.hasMessage(ErrorMessage.NOT_FOUND_COUPON.getMessage());
}
Expand Down
Loading