001package usecase.post; 002 003import media.MediaRepository; 004import media.ReadLimitExceededException; 005import media.validation.Image; 006import model.entity.Post; 007import model.entity.Section; 008import model.entity.User; 009import model.repository.GenericRepository; 010import model.repository.PostRepository; 011import model.validation.PostExists; 012import model.validation.SectionExists; 013import usecase.auth.AuthenticationRequired; 014import usecase.auth.AuthorizationException; 015import usecase.auth.CurrentUser; 016import usecase.auth.DenyBannedUsers; 017 018import javax.enterprise.context.ApplicationScoped; 019import javax.inject.Inject; 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.util.List; 028import java.util.stream.Collectors; 029 030import static model.entity.Post.Type.IMG; 031import static model.entity.Post.Type.TEXT; 032import static usecase.post.PostSearchForm.SortCriteria.NEWEST; 033 034/** 035 * Classe che fornisce i servizi relativi ai post. 036 */ 037@ApplicationScoped 038@Transactional 039public class PostService { 040 private GenericRepository genericRepository; 041 private PostRepository postRepo; 042 private MediaRepository bcRepo; 043 private CurrentUser currentUser; 044 045 protected PostService(){} 046 047 @Inject 048 protected PostService(GenericRepository genericRepository, PostRepository postRepo, 049 MediaRepository bcRepo, CurrentUser currentUser){ 050 this.genericRepository = genericRepository; 051 this.postRepo = postRepo; 052 this.bcRepo = bcRepo; 053 this.currentUser = currentUser; 054 } 055 056 /** 057 * Converte post in PostPage. 058 * @param post post da convertire 059 * @return PostPage con i dati di post 060 */ 061 private PostPage mapPost(Post post){ 062 User user = null; 063 if(currentUser.isLoggedIn()) 064 user = genericRepository.findById(User.class,currentUser.getId()); 065 066 //converte persistence.Post.Type in usecase.post.PostType (ew) 067 PostType postType = post.getType() == IMG ? PostType.IMG : PostType.TEXT; 068 069 return PostPage.builder() 070 .id(post.getId()) 071 .title(post.getTitle()) 072 .vote(post.getVote(user) == null ? 0 : post.getVote(user).getVote()) 073 .votes(post.getVotesCount() == null ? 0 : post.getVotesCount()) 074 .sectionName(post.getSection().getName()) 075 .authorName(post.getAuthor().getUsername()) 076 .sectionId(post.getSection().getId()) 077 .authorId(post.getAuthor().getId()) 078 .content(post.getContent()) 079 .creationDate(post.getCreationDate() == null ? Instant.now() : post.getCreationDate()) 080 .nComments(post.getCommentCount()) 081 .type(postType) 082 .build(); 083 } 084 085 /** 086 * Ritorna un entità DTO relativa ad un post 087 * @param id identificativo post 088 * @return DTO di un post 089 */ 090 public PostPage getPost(@PostExists int id){ 091 Post p = genericRepository.findById(Post.class,id); 092 return mapPost(p); 093 } 094 095 /** 096 * Ritorna una lista di post che rispettano determinati parametri 097 * @param form entità con i parametri di ricerca 098 * @return lista di PostPage 099 */ 100 @Transactional 101 public List<PostPage> loadPosts(PostSearchForm form){ 102 final int elementsPerPage = 10; 103 PostRepository.PostFinder finder = postRepo.getFinder(); 104 105 finder.limit(elementsPerPage); 106 107 int page = form.getPage() > 0 ? form.getPage() : 1; 108 finder.offset((page == 1) ? 0 : (page-1) * elementsPerPage+1); 109 110 if(form.getContent() != null) { 111 finder.byContent(form.getContent()); 112 } 113 if(form.isIncludeBody()){ 114 finder.includeBody(); 115 } 116 if(form.getSectionName() != null){ 117 Section section = genericRepository.findByNaturalId(Section.class, form.getSectionName()); 118 if(section != null){ 119 finder.bySection(section); 120 } 121 } 122 if(form.getAuthorName() != null){ 123 User user = genericRepository.findByNaturalId(User.class, form.getAuthorName()); 124 if(user != null){ 125 finder.byAuthor(user); 126 } 127 } 128 if(form.isOnlyFollow() && currentUser.isLoggedIn()){ 129 finder.joinUserFollows(genericRepository.findById(User.class,currentUser.getId())); 130 } 131 if(form.getPostedAfter() != null){ 132 finder.postedAfter(form.getPostedAfter()); 133 } 134 if(form.getPostedBefore() != null){ 135 finder.postedBefore(form.getPostedBefore()); 136 } 137 138 //null-safe switch 139 switch(form.getOrderBy() != null ? form.getOrderBy() : NEWEST){ 140 case NEWEST: default: { 141 finder.getNewest(); 142 break; 143 } 144 case OLDEST:{ 145 finder.getOldest(); 146 break; 147 } 148 case MOSTVOTED:{ 149 finder.getMostVoted(); 150 break; 151 } 152 } 153 return finder.getResults().stream().map(this::mapPost).collect(Collectors.toList()); 154 } 155 156 /** 157 * Elimina un post dato il suo id 158 * @param id identificativo del post 159 */ 160 @AuthenticationRequired //TODO: check autore post? 161 @DenyBannedUsers 162 public void delete(@PostExists int id){ 163 Post post = genericRepository.findById(Post.class,id); 164 if(currentUser.getId() != post.getAuthor().getId() && !currentUser.isAdmin()) 165 throw new AuthorizationException(); 166 genericRepository.remove(genericRepository.findById(User.class,id)); 167 } 168 169 /** 170 * Aggiunge un post ad una sezione 171 * @param title titolo del post 172 * @param body testo del post 173 * @param sectionName nome della sezione 174 * @return identificativo del nuovo post creato 175 */ 176 @AuthenticationRequired 177 @DenyBannedUsers 178 public int newPost(@NotBlank String title, 179 @Size(max=65535) String body, 180 @NotNull @SectionExists String sectionName){ 181 User user = genericRepository.findByNaturalId(User.class, currentUser.getUsername()); 182 Section section = genericRepository.findByNaturalId(Section.class,sectionName); 183 184 185 Post post = new Post(); 186 post.setTitle(title); 187 post.setContent(body == null || body.isBlank() ? "" : body); 188 post.setAuthor(user); 189 post.setSection(section); 190 post.setType(TEXT); 191 192 return genericRepository.insert(post).getId(); 193 } 194 195 /** 196 * Aggiunge un post ad una sezione 197 * @param title titolo del post 198 * @param content file di tipo immagine 199 * @param sectionName nome della sezione 200 * @return identificativo del nuovo post creato 201 */ 202 @AuthenticationRequired 203 @DenyBannedUsers 204 public int newPost(@NotBlank @Size(max=255) String title, 205 @NotNull @Image BufferedInputStream content, 206 @NotNull @SectionExists String sectionName){ 207 User user = genericRepository.findByNaturalId(User.class,currentUser.getUsername()); 208 Section section = genericRepository.findByNaturalId(Section.class,sectionName); 209 210 String fileName; 211 try { 212 fileName = bcRepo.insert(content); 213 } catch (ReadLimitExceededException e){ 214 throw new IllegalArgumentException("Il file non deve superare i 5MB"); 215 } catch (IOException e) { 216 throw new RuntimeException(e); 217 } 218 219 Post post = new Post(); 220 post.setTitle(title); 221 post.setAuthor(user); 222 post.setContent(fileName); 223 post.setSection(section); 224 post.setType(IMG); 225 226 return genericRepository.insert(post).getId(); //in caso di errore il file resta 227 } 228}