AdminService.java

package qwerty.chaekit.service.member.admin;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import qwerty.chaekit.domain.member.publisher.PublisherProfile;
import qwerty.chaekit.domain.member.publisher.PublisherProfileRepository;
import qwerty.chaekit.domain.member.publisher.enums.PublisherApprovalStatus;
import qwerty.chaekit.domain.member.user.UserProfile;
import qwerty.chaekit.domain.member.user.UserProfileRepository;
import qwerty.chaekit.dto.member.PublisherInfoResponse;
import qwerty.chaekit.dto.member.UserInfoResponse;
import qwerty.chaekit.dto.member.admin.RejectPublisherRequest;
import qwerty.chaekit.dto.page.PageResponse;
import qwerty.chaekit.global.enums.ErrorCode;
import qwerty.chaekit.global.exception.BadRequestException;
import qwerty.chaekit.global.exception.NotFoundException;
import qwerty.chaekit.service.util.EmailNotificationService;
import qwerty.chaekit.service.notification.NotificationService;
import qwerty.chaekit.service.util.FileService;

@Service
@Transactional
@RequiredArgsConstructor
public class AdminService {
    private final PublisherProfileRepository publisherRepository;
    private final EmailNotificationService emailNotificationService;
    private final FileService fileService;
    private final UserProfileRepository userRepository;
    private final NotificationService notificationService;

    @Getter
    @Setter
    private Long adminPublisherId;

    @Getter
    @Setter
    private Long adminUserId;

    @Transactional(readOnly = true)
    public PageResponse<PublisherInfoResponse> getPublishers(Pageable pageable) {
        Pageable pageableWithSort = getPageableOrderedByCreatedAt(pageable);
        Page<PublisherProfile> page = publisherRepository.findAll(pageableWithSort);
        return PageResponse.of(page.map(publisher -> PublisherInfoResponse.of(
                publisher,
                fileService.convertToPublicImageURL(publisher.getProfileImageKey())
        )));
    }

    @Transactional(readOnly = true)
    public PageResponse<UserInfoResponse> getUsers(Pageable pageable) {
        Pageable pageableWithSort = getPageableOrderedByCreatedAt(pageable);
        Page<UserProfile> page = userRepository.findAll(pageableWithSort);
        return PageResponse.of(page.map(user -> UserInfoResponse.of(
                user,
                fileService.convertToPublicImageURL(user.getProfileImageKey()),
                null, // 최근 활동 ID는 여기서 처리하지 않음
                null, // 최근 활동 책 이미지 URL은 여기서 처리하지 않음
                null,
                null
        )));
    }

    @Transactional(readOnly = true)
    public PageResponse<PublisherInfoResponse> getPendingPublishers(Pageable pageable) {
        Pageable pageableWithSort = getPageableOrderedByCreatedAt(pageable);
        Page<PublisherProfile> page = publisherRepository.findByApprovalStatus(
                PublisherApprovalStatus.PENDING,
                pageableWithSort
        );
        return PageResponse.of(page.map(publisher -> PublisherInfoResponse.of(
                        publisher,
                fileService.convertToPublicImageURL(publisher.getProfileImageKey())
                )));
    }

    @Transactional
    public void acceptPublisher(Long publisherId) {
        PublisherProfile publisher = publisherRepository.findByIdWithMember(publisherId)
                .orElseThrow(() -> new NotFoundException(ErrorCode.PUBLISHER_NOT_FOUND));
        UserProfile admin = userRepository.findById(adminUserId).orElseThrow(
                () -> new IllegalStateException("관리자 회원정보가 존재하지 않습니다")
        );

        // 이미 승인된 경우
        if (isPublisherApproved(publisher)) {
            throw new BadRequestException(ErrorCode.PUBLISHER_ALREADY_ACCEPTED);
        }

        // 승인 처리
        publisher.approvePublisher();
   
        notificationService.createPublisherApprovedNotification(publisher, admin);
        emailNotificationService.sendPublisherApprovalEmail(publisher.getMember().getEmail());
    }

    @Transactional
    public void rejectPublisher(Long publisherId, RejectPublisherRequest request) {
        PublisherProfile publisher = publisherRepository.findByIdWithMember(publisherId)
                .orElseThrow(() -> new NotFoundException(ErrorCode.PUBLISHER_NOT_FOUND));

        // 이미 승인된 경우
        if (isPublisherApproved(publisher)) {
            throw new BadRequestException(ErrorCode.PUBLISHER_ALREADY_ACCEPTED);
        }

        // 거절 처리
        publisher.rejectPublisher();

        UserProfile admin = userRepository.findById(adminUserId)
                .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND));
      
        emailNotificationService.sendPublisherRejectionEmail(publisher.getMember().getEmail(), request.reason());
    }

    private static Pageable getPageableOrderedByCreatedAt(Pageable pageable) {
        return PageRequest.of(
                pageable.getPageNumber(),
                pageable.getPageSize(),
                pageable.getSort().isEmpty() ? Sort.by(Sort.Order.desc("createdAt")) : pageable.getSort()
        );
    }

    private boolean isPublisherApproved(PublisherProfile publisher) {
        return publisher.getApprovalStatus().equals(PublisherApprovalStatus.APPROVED);
    }
}