001package usecase.section;
002
003import media.MediaRepository;
004import media.ReadLimitExceededException;
005import media.validation.Image;
006import model.entity.Section;
007import model.entity.User;
008import model.repository.GenericRepository;
009import model.repository.SectionRepository;
010import model.validation.SectionExists;
011import model.validation.UniqueSection;
012import usecase.auth.AdminsOnly;
013import usecase.auth.CurrentUser;
014
015import javax.enterprise.context.ApplicationScoped;
016import javax.enterprise.context.RequestScoped;
017import javax.enterprise.inject.Produces;
018import javax.inject.Inject;
019import javax.inject.Named;
020import javax.transaction.Transactional;
021import javax.validation.constraints.NotBlank;
022import javax.validation.constraints.NotNull;
023import javax.validation.constraints.Size;
024import java.io.BufferedInputStream;
025import java.io.IOException;
026import java.time.Instant;
027import java.time.temporal.ChronoUnit;
028import java.util.List;
029import java.util.Map;
030import java.util.stream.Collectors;
031
032/**
033 * Classe che fornisce i servizi relativi alle sezioni.
034 */
035@ApplicationScoped
036@Transactional
037public class SectionService {
038    private SectionRepository sectionRepo;
039    private GenericRepository genericRepository;
040    private MediaRepository bcRepo;
041    private CurrentUser currentUser;
042
043    protected SectionService(){}
044
045    @Inject
046    protected SectionService(GenericRepository genericRepository, SectionRepository sectionRepository,
047                             MediaRepository bcRepo, CurrentUser currentUser){
048        this.genericRepository = genericRepository;
049        this.sectionRepo = sectionRepository;
050        this.bcRepo = bcRepo;
051        this.currentUser = currentUser;
052    }
053
054    /**
055     * Converte section in SectionPage.
056     * @param section sezione da convertire
057     * @return SectionPage con i dati di section
058     */
059    private SectionPage map(Section section){
060        User user = null;
061        if(currentUser.isLoggedIn()){
062            user = genericRepository.findById(User.class,currentUser.getId());
063        }
064        return SectionPage.builder().id(section.getId())
065                .name(section.getName())
066                .picture(section.getPicture())
067                .description(section.getDescription())
068                .banner(section.getBanner())
069                .nFollowers(section.getFollowCount())
070                .isFollowed(user != null && section.getFollow(user) != null).build();
071    }
072
073    /**
074     * Cancella una sezione dato il suo id
075     * @param id l'id di una sezione esistente
076     */
077    @AdminsOnly
078    public void delete(@SectionExists int id){
079        genericRepository.remove(genericRepository.findById(Section.class, id));
080    }
081
082    /**
083     * Crea una nuova sezione e ne restituisce l'id
084     * @param name Nome della sezione
085     * @param description descrizione della sezione
086     * @param picture stream relativo alla foto della sezione
087     * @param banner stream relativo al banner della sezione
088     * @return id della sezione creata
089     */
090    @AdminsOnly
091    public int newSection(@NotBlank @Size(max=50) @UniqueSection String name,
092                          @Size(max=255) String description,
093                          @Image BufferedInputStream picture,
094                          @Image BufferedInputStream banner) {
095        Section s = new Section();
096        s.setName(name);
097        s.setDescription(description);
098        try {
099            if (picture != null)
100                s.setPicture(bcRepo.insert(picture));
101            if (banner != null)
102                s.setBanner(bcRepo.insert(banner));
103        } catch (ReadLimitExceededException e) {
104            throw new IllegalArgumentException("Il file non deve superare i 5MB");
105        } catch (IOException e) {
106            throw new RuntimeException(e);
107        }
108        return genericRepository.insert(s).getId();
109    }
110
111    /**
112     * Ritorna una lista di tutte le sezioni esistenti
113     * @return lista di sezioni
114     */
115    public List<SectionPage> showSections(){
116        return genericRepository.findAll(Section.class).stream().map(this::map).collect(Collectors.toList());
117    }
118
119    /**
120     * Ritorna una mappa di tutte le sezioni esistenti
121     * @return mappa la cui chiave è l'id della sezione e il valore un entita PostPage che ne contiene i dati
122     */
123    @Named("sections")
124    @RequestScoped
125    @Produces
126    public Map<Integer,SectionPage> getSectionsMap(){
127        return genericRepository.findAll(Section.class).stream().map(this::map)
128                .collect(Collectors.toMap(SectionPage::getId, section -> section));
129    }
130
131    /**
132     * Ritorna un entità sezione dato un certo id
133     * @param id id di una sezione esistente
134     * @return entita SectionPage che contiene i dati della sezione
135     */
136    public SectionPage showSection(@SectionExists int id){
137       Section s =  genericRepository.findById(Section.class, id);
138       return map(s);
139    }
140
141    /**
142     * Ritorna un entità sezione con un nome specifico
143     * @param sectionName nome di una sezione esistente
144     * @return entita SectionPage che contiene i dati della sezione
145     */
146    public SectionPage getSection(@NotNull @SectionExists String sectionName){
147        Section s = genericRepository.findByNaturalId(Section.class,sectionName);
148        return map(s);
149    }
150
151    /**
152     * Ritorna una lista delle sezioni con più follows
153     * @return lista di sezioni
154     */
155    @Produces
156    @RequestScoped
157    @Named("topSections")
158    public List<SectionPage> getTopSections(){
159        return sectionRepo.getMostFollowedSections().stream().map(this::map).collect(Collectors.toList());
160    }
161
162    /**
163     * Ritorna una lista delle sezioni con più follows negli ultimi 7 giorni
164     * @return lista di sezioni
165     */
166    @Produces
167    @RequestScoped
168    @Named("trendingSections")
169    public List<SectionPage> getTrendingSections(){
170        return sectionRepo.getMostFollowedSections(Instant.now().minus(7, ChronoUnit.DAYS))
171                .stream().map(this::map).collect(Collectors.toList());
172    }
173}