Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.assu.server.domain.auth.exception.CustomAuthException;
import com.assu.server.domain.auth.repository.CommonAuthRepository;
import com.assu.server.domain.auth.security.userdetails.CommonUserDetails;
import com.assu.server.domain.auth.service.WithdrawalService;
import com.assu.server.domain.common.enums.ActivationStatus;
import com.assu.server.domain.member.entity.Member;
import com.assu.server.domain.member.repository.MemberRepository;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -25,7 +25,7 @@
public class CommonAuthAdapter implements RealmAuthAdapter {

private final CommonAuthRepository commonAuthRepository;
private final MemberRepository memberRepository;
private final WithdrawalService withdrawalService;
private final PasswordEncoder passwordEncoder;

@Override
Expand Down Expand Up @@ -70,8 +70,7 @@ public Member loadMember(String email) {
commonAuthRepository.save(commonAuth);

if (member.isWithdrawn()) {
member.restore();
memberRepository.save(member);
withdrawalService.restoreMember(member);
}

return member;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class SignUpServiceImpl implements SignUpService {
private final PhoneAuthService phoneAuthService;
private final CommonAuthRepository commonAuthRepository;
private final DiscordNotifier discordNotifier;
private final WithdrawalService withdrawalService;

private RealmAuthAdapter pickAdapter(AuthRealm realm) {
return realmAuthAdapters.stream()
Expand Down Expand Up @@ -276,7 +277,7 @@ private SignUpResponseDTO restoreWithdrawnPartner(
}

// isActivated는 유지한다 — 승인받았던 업체는 재승인 없이 바로 로그인 가능
member.restore();
withdrawalService.restoreMember(member);
member.updateTermAgreements(req.locationAgree(), req.marketingAgree());
memberRepository.save(member);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public interface WithdrawalService {
void withdrawCurrentUser(String authorization);
void withdrawMember(Long memberId);
void withdrawMember(Member member);
void restoreMember(Member member);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package com.assu.server.domain.auth.service;

import com.assu.server.domain.auth.security.jwt.JwtUtil;
import com.assu.server.domain.common.enums.ActivationStatus;
import com.assu.server.domain.common.enums.UserRole;
import com.assu.server.domain.deviceToken.repository.DeviceTokenRepository;
import com.assu.server.domain.member.entity.Member;
import com.assu.server.domain.member.repository.MemberRepository;
import com.assu.server.domain.auth.exception.CustomAuthException;
import com.assu.server.domain.partnership.repository.PaperRepository;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
import io.jsonwebtoken.Claims;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor
Expand All @@ -20,6 +25,7 @@ public class WithdrawalServiceImpl implements WithdrawalService {

private final MemberRepository memberRepository;
private final DeviceTokenRepository deviceTokenRepository;
private final PaperRepository paperRepository;
private final JwtUtil jwtUtil;

@Override
Expand Down Expand Up @@ -50,8 +56,26 @@ public void withdrawMember(Member member) {
member.withdraw();
memberRepository.save(member);

if (member.getRole() == UserRole.PARTNER) {
paperRepository.deactivateByPartnerWithdrawal(
member.getId(),
List.of(ActivationStatus.ACTIVE, ActivationStatus.SUSPEND),
ActivationStatus.INACTIVE
);
}

deviceTokenRepository.deleteAllByMemberId(member.getId());
jwtUtil.removeAllRefreshTokens(member.getId());
jwtUtil.revokeAllAccessTokensSince(member.getId());
}

@Override
public void restoreMember(Member member) {
member.restore();
memberRepository.save(member);

if (member.getRole() == UserRole.PARTNER) {
paperRepository.restoreByPartnerRestoration(member.getId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public BackofficeMemberSummaryDTO restoreMember(Long memberId) {
throw new CustomAuthException(ErrorStatus.MEMBER_NOT_DELETED);
}

member.restore();
withdrawalService.restoreMember(member);
return BackofficeMemberSummaryDTO.from(loadProfileForSummary(member));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C

Admin admin = adminRepository.findById(adminId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
Partner partner = partnerRepository.findById(partnerId)
Partner partner = partnerRepository.findByIdAndMember_DeletedAtIsNull(partnerId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_PARTNER));
Store store = storeRepository.findByPartnerId(partnerId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_STORE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface PartnerRepository extends JpaRepository<Partner, Long> {

boolean existsByPhoneNum(String phoneNum);

boolean existsByPhoneNumAndMember_DeletedAtIsNull(String phoneNum);

Optional<Partner> findByIdAndMember_DeletedAtIsNull(Long id);

@Query("""
SELECT COUNT(p)
FROM Partner p
WHERE NOT EXISTS (
WHERE p.member.deletedAt IS NULL
AND NOT EXISTS (
SELECT 1 FROM Paper pa
WHERE pa.partner = p
AND pa.admin.id = :adminId
Expand All @@ -29,7 +33,8 @@ WHERE NOT EXISTS (
@Query("""
SELECT p
FROM Partner p
WHERE NOT EXISTS (
WHERE p.member.deletedAt IS NULL
AND NOT EXISTS (
SELECT 1 FROM Paper pa
WHERE pa.partner = p
AND pa.admin.id = :adminId
Expand All @@ -42,8 +47,9 @@ WHERE NOT EXISTS (
@Query("""
SELECT DISTINCT p
FROM Partner p
LEFT JOIN FETCH p.member
WHERE p.point IS NOT NULL
LEFT JOIN FETCH p.member m
WHERE m.deletedAt IS NULL
AND p.point IS NOT NULL
AND ST_Contains(ST_GeomFromText(:wkt, 4326), p.point) = true
""")
List<Partner> findAllWithinViewportWithMember(@Param("wkt") String wkt);
Expand All @@ -52,8 +58,9 @@ AND ST_Contains(ST_GeomFromText(:wkt, 4326), p.point) = true
@Query("""
SELECT DISTINCT p
FROM Partner p
LEFT JOIN FETCH p.member
WHERE LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%'))
LEFT JOIN FETCH p.member m
WHERE m.deletedAt IS NULL
AND LOWER(p.name) LIKE LOWER(CONCAT('%', :keyword, '%'))
""")
List<Partner> searchPartnerByKeywordWithMember(
@Param("keyword") String keyword
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,9 @@ public class Paper extends BaseEntity {
@Column(name = "contract_image_key", length = 512)
private String contractImageKey;

@Enumerated(EnumType.STRING)
@Column(name = "status_before_partner_withdrawal")
private ActivationStatus statusBeforePartnerWithdrawal;

public void updateContractImageKey(String key) { this.contractImageKey = key; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,26 @@ void updatePaperStatus(@Param("today") LocalDate today,
@Param("inactiveStatus") ActivationStatus inactiveStatus,
@Param("activeStatus") ActivationStatus activeStatus);

@Modifying(flushAutomatically = true)
@Query("""
UPDATE Paper p
SET p.statusBeforePartnerWithdrawal = p.isActivated,
p.isActivated = :inactiveStatus
WHERE p.partner.id = :partnerId
AND p.isActivated IN :targetStatuses
""")
void deactivateByPartnerWithdrawal(@Param("partnerId") Long partnerId,
@Param("targetStatuses") List<ActivationStatus> targetStatuses,
@Param("inactiveStatus") ActivationStatus inactiveStatus);

@Modifying(flushAutomatically = true)
@Query("""
UPDATE Paper p
SET p.isActivated = p.statusBeforePartnerWithdrawal,
p.statusBeforePartnerWithdrawal = null
WHERE p.partner.id = :partnerId
AND p.statusBeforePartnerWithdrawal IS NOT NULL
""")
void restoreByPartnerRestoration(@Param("partnerId") Long partnerId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ public ManualPartnershipResponseDTO createManualPartnership(
public PartnershipDraftResponseDTO createDraftPartnership(PartnershipDraftRequestDTO request, Long adminId) {
Admin admin = adminRepository.findById(adminId)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN));
Partner partner = partnerRepository.findById(request.partnerId())
Partner partner = partnerRepository.findByIdAndMember_DeletedAtIsNull(request.partnerId())
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_PARTNER));
Store store = storeRepository.findByPartner(partner)
.orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_STORE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
import com.assu.server.domain.member.repository.MemberRepository;
import com.assu.server.domain.partner.entity.Partner;
import com.assu.server.domain.partner.repository.PartnerRepository;
import com.assu.server.domain.partnership.entity.Paper;
import com.assu.server.domain.partnership.repository.PaperRepository;
import com.assu.server.domain.store.entity.Store;
import com.assu.server.domain.store.repository.StoreRepository;
import com.assu.server.global.apiPayload.code.status.ErrorStatus;
import com.assu.server.support.CommonMockConfig;
import jakarta.persistence.EntityManager;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -22,6 +25,8 @@
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

Expand All @@ -46,6 +51,12 @@ class BackofficeMemberServiceTest {
@Autowired
private StoreRepository storeRepository;

@Autowired
private PaperRepository paperRepository;

@Autowired
private EntityManager entityManager;

@Test
@DisplayName("SUSPEND Partner 회원을 승인하면 ACTIVE 및 license verified 처리")
void approvePartnerMember() {
Expand Down Expand Up @@ -118,6 +129,53 @@ void cannotApproveActiveMember() {
.isEqualTo(ErrorStatus.MEMBER_NOT_PENDING_APPROVAL);
}

@Test
@DisplayName("제휴업체를 강제 탈퇴시키면 ACTIVE/SUSPEND 제휴만 INACTIVE가 되고, 복구하면 원래 상태로 돌아온다")
void forceWithdrawAndRestorePartner_TogglesPartnerPapers() {
Member member = createPartnerMember(ActivationStatus.ACTIVE);
Partner partner = member.getPartnerProfile();
Store store = storeRepository.findByPartner(partner).orElseThrow();

Long activeId = createPaper(partner, store, ActivationStatus.ACTIVE).getId();
Long suspendId = createPaper(partner, store, ActivationStatus.SUSPEND).getId();
Long inactiveId = createPaper(partner, store, ActivationStatus.INACTIVE).getId();
Long manualId = createPaper(null, store, ActivationStatus.ACTIVE).getId();

backofficeMemberService.forceWithdrawMember(member.getId());
entityManager.flush();
entityManager.clear();

assertThat(findPaper(activeId).getIsActivated()).isEqualTo(ActivationStatus.INACTIVE);
assertThat(findPaper(suspendId).getIsActivated()).isEqualTo(ActivationStatus.INACTIVE);
assertThat(findPaper(inactiveId).getIsActivated()).isEqualTo(ActivationStatus.INACTIVE);
assertThat(findPaper(inactiveId).getStatusBeforePartnerWithdrawal()).isNull();
assertThat(findPaper(manualId).getIsActivated()).isEqualTo(ActivationStatus.ACTIVE);

backofficeMemberService.restoreMember(member.getId());
entityManager.flush();
entityManager.clear();

assertThat(findPaper(activeId).getIsActivated()).isEqualTo(ActivationStatus.ACTIVE);
assertThat(findPaper(suspendId).getIsActivated()).isEqualTo(ActivationStatus.SUSPEND);
assertThat(findPaper(inactiveId).getIsActivated()).isEqualTo(ActivationStatus.INACTIVE);
assertThat(findPaper(activeId).getStatusBeforePartnerWithdrawal()).isNull();
assertThat(findPaper(manualId).getIsActivated()).isEqualTo(ActivationStatus.ACTIVE);
}

private Paper createPaper(Partner partner, Store store, ActivationStatus status) {
return paperRepository.save(Paper.builder()
.partner(partner)
.store(store)
.isActivated(status)
.partnershipPeriodStart(LocalDate.now().minusDays(1))
.partnershipPeriodEnd(LocalDate.now().plusDays(30))
.build());
}

private Paper findPaper(Long paperId) {
return paperRepository.findById(paperId).orElseThrow();
}

private Member createPartnerMember(ActivationStatus status) {
Member member = memberRepository.save(Member.builder()
.role(UserRole.PARTNER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ class SignUpServiceImplTest {
@Mock
private PasswordEncoder passwordEncoder;

@Mock
private WithdrawalService withdrawalService;

private static final String PHONE = "01012345678";
private static final String MASTER_PHONE = "01000000000";
private static final String EMAIL = "partner@assu.site";
Expand All @@ -124,7 +127,7 @@ void setUp() {
memberRepository, studentRepository, partnerRepository, adminRepository,
List.of(realmAuthAdapter), amazonS3Manager, jwtUtil,
new GeometryFactory(), storeRepository, ssuAuthService, ssuAuthRepository,
studentService, phoneAuthService, commonAuthRepository, discordNotifier);
studentService, phoneAuthService, commonAuthRepository, discordNotifier, withdrawalService);
}

@AfterEach
Expand Down Expand Up @@ -478,7 +481,7 @@ void signupPartner_WithdrawnPartner_RestoresAccountKeepingActivationStatus() {
SignUpResponseDTO response = signUpService.signupPartner(request, licenseImage);

// 3. Then
verify(member, times(1)).restore();
verify(withdrawalService, times(1)).restoreMember(member);
verify(member, never()).setIsActivated(any());
verify(commonAuth, times(1)).updatePassword("hashed");
verify(partner, times(1)).updateBusinessInfo(
Expand Down
Loading
Loading