SectionService.java

package usecase.section;

import media.MediaRepository;
import media.ReadLimitExceededException;
import media.validation.Image;
import model.entity.Section;
import model.entity.User;
import model.repository.GenericRepository;
import model.repository.SectionRepository;
import model.validation.SectionExists;
import model.validation.UniqueSection;
import usecase.auth.AdminsOnly;
import usecase.auth.CurrentUser;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.inject.Named;
import javax.transaction.Transactional;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Classe che fornisce i servizi relativi alle sezioni.
 */
@ApplicationScoped
@Transactional
public class SectionService {
    private SectionRepository sectionRepo;
    private GenericRepository genericRepository;
    private MediaRepository bcRepo;
    private CurrentUser currentUser;

    protected SectionService(){}

    @Inject
    protected SectionService(GenericRepository genericRepository, SectionRepository sectionRepository,
                             MediaRepository bcRepo, CurrentUser currentUser){
        this.genericRepository = genericRepository;
        this.sectionRepo = sectionRepository;
        this.bcRepo = bcRepo;
        this.currentUser = currentUser;
    }

    /**
     * Converte section in SectionPage.
     * @param section sezione da convertire
     * @return SectionPage con i dati di section
     */
    private SectionPage map(Section section){
        User user = null;
        if(currentUser.isLoggedIn()){
            user = genericRepository.findById(User.class,currentUser.getId());
        }
        return SectionPage.builder().id(section.getId())
                .name(section.getName())
                .picture(section.getPicture())
                .description(section.getDescription())
                .banner(section.getBanner())
                .nFollowers(section.getFollowCount())
                .isFollowed(user != null && section.getFollow(user) != null).build();
    }

    /**
     * Cancella una sezione dato il suo id
     * @param id l'id di una sezione esistente
     */
    @AdminsOnly
    public void delete(@SectionExists int id){
        genericRepository.remove(genericRepository.findById(Section.class, id));
    }

    /**
     * Crea una nuova sezione e ne restituisce l'id
     * @param name Nome della sezione
     * @param description descrizione della sezione
     * @param picture stream relativo alla foto della sezione
     * @param banner stream relativo al banner della sezione
     * @return id della sezione creata
     */
    @AdminsOnly
    public int newSection(@NotBlank @Size(max=50) @UniqueSection String name,
                          @Size(max=255) String description,
                          @Image BufferedInputStream picture,
                          @Image BufferedInputStream banner) {
        Section s = new Section();
        s.setName(name);
        s.setDescription(description);
        try {
            if (picture != null)
                s.setPicture(bcRepo.insert(picture));
            if (banner != null)
                s.setBanner(bcRepo.insert(banner));
        } catch (ReadLimitExceededException e) {
            throw new IllegalArgumentException("Il file non deve superare i 5MB");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return genericRepository.insert(s).getId();
    }

    /**
     * Ritorna una lista di tutte le sezioni esistenti
     * @return lista di sezioni
     */
    public List<SectionPage> showSections(){
        return genericRepository.findAll(Section.class).stream().map(this::map).collect(Collectors.toList());
    }

    /**
     * Ritorna una mappa di tutte le sezioni esistenti
     * @return mappa la cui chiave è l'id della sezione e il valore un entita PostPage che ne contiene i dati
     */
    @Named("sections")
    @RequestScoped
    @Produces
    public Map<Integer,SectionPage> getSectionsMap(){
        return genericRepository.findAll(Section.class).stream().map(this::map)
                .collect(Collectors.toMap(SectionPage::getId, section -> section));
    }

    /**
     * Ritorna un entità sezione dato un certo id
     * @param id id di una sezione esistente
     * @return entita SectionPage che contiene i dati della sezione
     */
    public SectionPage showSection(@SectionExists int id){
       Section s =  genericRepository.findById(Section.class, id);
       return map(s);
    }

    /**
     * Ritorna un entità sezione con un nome specifico
     * @param sectionName nome di una sezione esistente
     * @return entita SectionPage che contiene i dati della sezione
     */
    public SectionPage getSection(@NotNull @SectionExists String sectionName){
        Section s = genericRepository.findByNaturalId(Section.class,sectionName);
        return map(s);
    }

    /**
     * Ritorna una lista delle sezioni con più follows
     * @return lista di sezioni
     */
    @Produces
    @RequestScoped
    @Named("topSections")
    public List<SectionPage> getTopSections(){
        return sectionRepo.getMostFollowedSections().stream().map(this::map).collect(Collectors.toList());
    }

    /**
     * Ritorna una lista delle sezioni con più follows negli ultimi 7 giorni
     * @return lista di sezioni
     */
    @Produces
    @RequestScoped
    @Named("trendingSections")
    public List<SectionPage> getTrendingSections(){
        return sectionRepo.getMostFollowedSections(Instant.now().minus(7, ChronoUnit.DAYS))
                .stream().map(this::map).collect(Collectors.toList());
    }
}