ReadingProgressService.java

package qwerty.chaekit.service.ebook;

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import qwerty.chaekit.domain.ebook.Ebook;
import qwerty.chaekit.domain.ebook.purchase.EbookPurchase;
import qwerty.chaekit.domain.ebook.purchase.repository.EbookPurchaseRepository;
import qwerty.chaekit.domain.group.activity.Activity;
import qwerty.chaekit.domain.group.activity.activitymember.ActivityMember;
import qwerty.chaekit.domain.group.activity.activitymember.ActivityMemberRepository;
import qwerty.chaekit.domain.member.user.UserProfile;
import qwerty.chaekit.dto.ebook.purchase.ReadingProgressRequest;
import qwerty.chaekit.dto.ebook.purchase.ReadingProgressResponse;
import qwerty.chaekit.dto.page.PageResponse;
import qwerty.chaekit.global.enums.ErrorCode;
import qwerty.chaekit.global.exception.ForbiddenException;
import qwerty.chaekit.global.security.resolver.UserToken;
import qwerty.chaekit.mapper.ReadingProgressMapper;
import qwerty.chaekit.service.util.EntityFinder;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional
public class ReadingProgressService {
    
    private final EbookPurchaseRepository ebookPurchaseRepository;
    private final ActivityMemberRepository activityMemberRepository;
    private final ReadingProgressMapper readingProgressMapper;
    private final EntityFinder entityFinder;


    @Transactional
    public void saveMyProgress(UserToken userToken, Long bookId, ReadingProgressRequest request) {
        UserProfile user = entityFinder.findUser(userToken.userId());
        Ebook ebook = entityFinder.findEbook(bookId);

        EbookPurchase ebookPurchase = ebookPurchaseRepository.findByUserAndEbook(user, ebook)
                .orElseThrow(() -> new ForbiddenException(ErrorCode.EBOOK_NOT_PURCHASED));

        ebookPurchase.saveProgress(request.cfi(), request.percentage());
    }

    public ReadingProgressResponse getMyProgress(UserToken userToken, Long bookId) {
        UserProfile user = entityFinder.findUser(userToken.userId());
        Ebook ebook = entityFinder.findEbook(bookId);

        EbookPurchase ebookPurchase = ebookPurchaseRepository.findByUserAndEbook(user,ebook)
                .orElseThrow(() -> new ForbiddenException(ErrorCode.EBOOK_NOT_PURCHASED));

        return readingProgressMapper.toResponse(ebookPurchase);
    }

    public PageResponse<ReadingProgressResponse> getProgressFromActivity(Long activityId, Pageable pageable) {
        Activity activity = entityFinder.findActivity(activityId);

        Page<ActivityMember> activityMembers = activityMemberRepository.findByActivity(activity, pageable);
        List<Long> userIdList = activityMembers
                .map(activityMember -> activityMember.getUser().getId())
                .stream().toList();
        List<EbookPurchase> purchaseList = ebookPurchaseRepository.findByUserIdInAndEbook(userIdList, activity.getBook());
        Page<EbookPurchase> ebookPurchases = new PageImpl<>(purchaseList, pageable, purchaseList.size());

        return PageResponse.of(ebookPurchases.map(readingProgressMapper::toResponse));
    }
}