VoteService.java

/*
 * Copyright © 2025 The CTAN Team and individual authors
 *
 * This file is distributed under the 3-clause BSD license.
 * See file LICENSE for details.
 */
package org.ctan.site.services.catalogue;

import java.util.List;
import java.util.stream.Collectors;

import org.ctan.site.domain.account.User;
import org.ctan.site.domain.account.User.PrintableUser;
import org.ctan.site.domain.catalogue.Pkg;
import org.ctan.site.domain.site.Vote;
import org.ctan.site.stores.VoteStore;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;

/**
 * This service deals with votes.
 *
 * @author <a href="mailto:gene@ctan.org">Gerd Neugebauer</a>
 */
public final class VoteService {

    /**
     * The class <code>VoteSummaryTo</code> contains the transport object for
     * the vote resource in the summary list.
     */
    @Getter
    @Builder
    @AllArgsConstructor
    @JsonInclude(Include.NON_NULL)
    @SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
    public static class VoteSummaryTo {

        private int[] ratings;

        private List<VoteTo> list;

        private int count;
    }

    /**
     * The class <code>VoteTo</code> contains the transport object for the vote.
     */
    @Getter
    @Builder
    @AllArgsConstructor
    @JsonInclude(Include.NON_NULL)
    @SuppressFBWarnings(value = "EI_EXPOSE_REP")
    public static class VoteTo {

        private String pkg;

        private int rating;

        private int expertise;

        private String comment;

        private String account;

        private String user;

        private String date;
    }

    /**
     * The field <code>voteStore</code> contains the vote store.
     */
    private VoteStore voteStore;

    /**
     * This is the constructor for <code>VoteService</code>.
     *
     * @param voteStore the vote store
     */
    @SuppressFBWarnings(value = "EI_EXPOSE_REP2")
    public VoteService(@NonNull VoteStore voteStore) {

        this.voteStore = voteStore;
    }

    /**
     * The method <code>find</code> provides means to retrieve the votes for a
     * user.
     *
     * @param pkg the user
     * @param page the current page to retrieve
     * @param size the page size
     * @return the list and rating summary
     */
    public VoteSummaryTo find(Pkg pkg, long page, long size) {

        List<Vote> votes = voteStore.findByPkg(pkg);
        return prepareVotes(votes, page, size);
    }

    /**
     * The method <code>find</code> provides means to retrieve the votes for a
     * package.
     *
     * @param user the package
     * @param page the current page to retrieve
     * @param size the page size
     * @return the list and rating summary
     */
    public VoteSummaryTo find(User user, long page, long size) {

        List<Vote> votes = voteStore.findByAccount(user);
        return prepareVotes(votes, page, size);
    }

    /**
     * The method <code>prepareVotes</code> provides means to prepare a list of
     * votes.
     *
     * @param votes the list of all votes
     * @param page the current page
     * @param size the page size
     *
     * @return the vote summary
     */
    private VoteSummaryTo prepareVotes(List<Vote> votes, long page, long size) {

        int length = votes.size();
        int[] ratings = new int[]{0, 0, 0, 0, 0, 0};
        for (var it : votes) {
            ratings[it.getRating()]++;
        }
        List<VoteTo> list = votes
            .stream()
            .sorted(
                (a, b) -> a.getLastModified().compareTo(b.getLastModified()))
            .skip(page * size)
            .limit(size)
            .map((Vote a) -> {
                PrintableUser printable = a.getUser().getPrintable();
                return VoteTo.builder()
                    .account(printable.getAccount())
                    .comment(a.getComment())
                    .date(a.getDate())
                    .expertise(a.getExpertise())
                    .pkg(a.getPkg().getKey())
                    .rating(a.getRating())
                    .user(printable.getName())
                    .build();
            })
            .collect(Collectors.toList());
        return VoteSummaryTo.builder()
            .ratings(ratings)
            .list(list)
            .count(length)
            .build();
    }
}