diff --git a/pom.xml b/pom.xml index 922207e..08e9451 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ UTF-8 11 - 1.0.0 + 1.0.1 diff --git a/src/main/java/de/bstly/board/businesslogic/BookmarksManager.java b/src/main/java/de/bstly/board/businesslogic/BookmarksManager.java index 6503769..1d37a39 100644 --- a/src/main/java/de/bstly/board/businesslogic/BookmarksManager.java +++ b/src/main/java/de/bstly/board/businesslogic/BookmarksManager.java @@ -99,4 +99,17 @@ public class BookmarksManager { } } + /** + * Removes the entry. + * + * @param entryId the entry id + */ + public void removeEntry(Long entryId) { + for (Bookmarks bookmarks : bookmarksRepository + .findAll(qBookmarks.entries.contains(entryId))) { + bookmarks.getEntries().remove(entryId); + bookmarksRepository.save(bookmarks); + } + } + } diff --git a/src/main/java/de/bstly/board/businesslogic/CommentManager.java b/src/main/java/de/bstly/board/businesslogic/CommentManager.java index b8db280..dea020f 100644 --- a/src/main/java/de/bstly/board/businesslogic/CommentManager.java +++ b/src/main/java/de/bstly/board/businesslogic/CommentManager.java @@ -283,6 +283,7 @@ public class CommentManager { } voteManager.deleteByTarget(comment.getId(), Types.comment); + flagManager.deleteByTarget(comment.getId(), Types.comment); commentRepository.delete(comment); } diff --git a/src/main/java/de/bstly/board/businesslogic/EntryManager.java b/src/main/java/de/bstly/board/businesslogic/EntryManager.java index d25d7f7..4568d9d 100644 --- a/src/main/java/de/bstly/board/businesslogic/EntryManager.java +++ b/src/main/java/de/bstly/board/businesslogic/EntryManager.java @@ -3,9 +3,13 @@ */ package de.bstly.board.businesslogic; +import java.math.BigInteger; import java.time.Instant; import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.Query; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; @@ -21,11 +25,10 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import de.bstly.board.model.Bookmarks; import de.bstly.board.model.Entry; -import de.bstly.board.model.EntryStatus; +import de.bstly.board.model.FlaggedStatus; import de.bstly.board.model.QEntry; import de.bstly.board.model.QFlag; import de.bstly.board.model.QVote; -import de.bstly.board.model.RankedEntry; import de.bstly.board.model.Types; import de.bstly.board.model.VoteType; import de.bstly.board.repository.EntryRepository; @@ -53,61 +56,195 @@ public class EntryManager { private FlagManager flagManager; @Autowired private JPAQueryFactory jpaQueryFactory; + @Autowired + private EntityManager em; private QEntry qEntry = QEntry.entry; private QVote qVote = QVote.vote; private QFlag qFlag = QFlag.flag; + static final String UPVOTES_QUERY = "SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 1 GROUP BY upvote.target"; + + static final String DOWNVOTES_QUERY = "SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 AND downvote.target_type = 1 GROUP BY downvote.target"; + + static final String COMMENTS_QUERY = "SELECT comment.target,MAX(comment.created) as last,COUNT(comment.id) AS count FROM comments as comment WHERE comment.flagged_status = :flag GROUP BY comment.target"; + + static final String RANK_CALCULATION_QUERY = "SELECT entry.*, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) as points, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / IF(:gravity > 0, POW(TIMESTAMPDIFF(HOUR, entry.created, :before)+2,:gravity), 1) AS ranking FROM entries AS entry LEFT JOIN (" + + UPVOTES_QUERY + + ") AS upvote ON upvote.target = entry.id LEFT JOIN (" + + DOWNVOTES_QUERY + + ") AS downvote ON downvote.target = entry.id WHERE %s ORDER BY ranking DESC, entry.created DESC"; + + static final String DATE_QUERY = "SELECT entry.*FROM entries AS entry WHERE %s ORDER BY entry.created DESC"; + + static final String COMMENT_CALCULATION_QUERY = "SELECT entry.*, IFNULL(comment.count,0) as comments, IFNULL(comment.count,0) / IF(:gravity > 0, POW(TIMESTAMPDIFF(HOUR, comment.last, :before)+2,:gravity), 1) AS ranking FROM entries AS entry LEFT JOIN (" + + COMMENTS_QUERY + + ") AS comment ON comment.target = entry.id WHERE %s ORDER BY ranking DESC, entry.created DESC"; + + static final String LAST_COMMENT_QUERY = "SELECT entry.* FROM entries AS entry LEFT JOIN (" + + COMMENTS_QUERY + + ") AS comment ON comment.target = entry.id WHERE %s ORDER BY comment.last DESC, entry.created DESC"; + + static final String COUNT_QUERY = "SELECT count(entry.id) FROM entries as entry WHERE %s"; + /** * Fetch by ranking. * - * @param date the date - * @param gravity the gravity - * @param page the page - * @param size the size + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @param gravity the gravity + * @param page the page + * @param size the size * @return the page */ - public Page fetchByRanking(Instant date, double gravity, int page, int size) { - return entryRepository.findAllByRanking(date, gravity, PageRequest.of(page, size)); - } - - /** - * Fetch by comments. - * - * @param date the date - * @param gravity the gravity - * @param page the page - * @param size the size - * @return the page - */ - public Page fetchByComments(Instant date, double gravity, int page, int size) { - return entryRepository.findAllByComments(date, gravity, PageRequest.of(page, size)); - } - - /** - * Fetch by last comment. - * - * @param date the date - * @param page the page - * @param size the size - * @return the page - */ - public Page fetchByLastComment(Instant date, int page, int size) { - return entryRepository.findAllByLastComment(date, PageRequest.of(page, size)); + public Page fetchByRanking(String username, Instant date, FlaggedStatus flaggedStatus, + double gravity, int page, int size) { + Query query = createEntryQuery(RANK_CALCULATION_QUERY, username, date, flaggedStatus); + query.setParameter("gravity", gravity); + query.setFirstResult((page) * size); + query.setMaxResults(size); + @SuppressWarnings("unchecked") + List list = query.getResultList(); + Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus); + long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue(); + return new PageImpl(list, PageRequest.of(page, size), countResult); } /** * Fetch by date. * - * @param date the date - * @param page the page - * @param size the size + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @param page the page + * @param size the size * @return the page */ - public Page fetchByDate(Instant date, int page, int size) { - return entryRepository.findAll( - qEntry.created.before(date).and(qEntry.entryStatus.eq(EntryStatus.NORMAL)), - PageRequest.of(page, size, Sort.by(Order.desc("created")))); + public Page fetchByDate(String username, Instant date, FlaggedStatus flaggedStatus, + int page, int size) { + Query query = createEntryQuery(DATE_QUERY, username, date, flaggedStatus); + query.setFirstResult((page) * size); + query.setMaxResults(size); + @SuppressWarnings("unchecked") + List list = query.getResultList(); + Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus); + long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue(); + return new PageImpl(list, PageRequest.of(page, size), countResult); + } + + /** + * Fetch by comments. + * + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @param gravity the gravity + * @param page the page + * @param size the size + * @return the page + */ + public Page fetchByComments(String username, Instant date, FlaggedStatus flaggedStatus, + double gravity, int page, int size) { + Query query = createEntryQuery(COMMENT_CALCULATION_QUERY, username, date, flaggedStatus); + query.setParameter("gravity", gravity); + query.setFirstResult((page) * size); + query.setMaxResults(size); + @SuppressWarnings("unchecked") + List list = query.getResultList(); + Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus); + long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue(); + return new PageImpl(list, PageRequest.of(page, size), countResult); + } + + /** + * Fetch by last comment. + * + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @param page the page + * @param size the size + * @return the page + */ + public Page fetchByLastComment(String username, Instant date, + FlaggedStatus flaggedStatus, int page, int size) { + Query query = createEntryQuery(LAST_COMMENT_QUERY, username, date, flaggedStatus); + query.setFirstResult((page) * size); + query.setMaxResults(size); + @SuppressWarnings("unchecked") + List list = query.getResultList(); + Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus); + long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue(); + return new PageImpl(list, PageRequest.of(page, size), countResult); + } + + /** + * Creates the entry query. + * + * @param rawQuery the raw query + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @return the query + */ + protected Query createEntryQuery(String rawQuery, String username, Instant date, + FlaggedStatus flaggedStatus) { + String filterString = ""; + + boolean author = false; + if (date != null) { + filterString = "entry.created < :before"; + } else { + date = Instant.now(); + author = true; + filterString = "(entry.created < :before OR entry.author = :author)"; + } + + filterString += " AND entry.flagged_status = :flag"; + + Query query = em.createNativeQuery(String.format(rawQuery, filterString), Entry.class); + query.setParameter("before", date); + if (author) { + query.setParameter("author", username); + } + query.setParameter("flag", flaggedStatus.toString()); + + return query; + } + + /** + * Creates the count query. + * + * @param rawQuery the raw query + * @param username the username + * @param date the date + * @param flaggedStatus the flagged status + * @return the query + */ + protected Query createCountQuery(String rawQuery, String username, Instant date, + FlaggedStatus flaggedStatus) { + String filterString = ""; + + boolean author = false; + if (date != null) { + filterString = "entry.created < :before"; + } else { + date = Instant.now(); + author = true; + filterString = "(entry.created < :before OR entry.author = :author)"; + } + + filterString += " AND entry.flagged_status = :flag"; + + Query query = em.createNativeQuery(String.format(rawQuery, filterString)); + query.setParameter("before", date); + if (author) { + query.setParameter("author", username); + } + query.setParameter("flag", flaggedStatus.toString()); + + return query; } /** @@ -115,7 +252,7 @@ public class EntryManager { * * @param page the page * @param size the size - * @param asc the asc + * @param asc the asc * @return the page */ public Page fetchFlagged(int page, int size, boolean asc) { @@ -134,10 +271,10 @@ public class EntryManager { * Fetch by user. * * @param username the username - * @param date the date - * @param page the page - * @param size the size - * @param asc the asc + * @param date the date + * @param page the page + * @param size the size + * @param asc the asc * @return the page */ public Page fetchByUser(String username, Instant date, int page, int size, boolean asc) { @@ -151,8 +288,8 @@ public class EntryManager { * Fetch by bookmarks. * * @param username the username - * @param page the page - * @param size the size + * @param page the page + * @param size the size * @return the page */ public Page fetchByBookmarks(String username, int page, int size) { @@ -170,9 +307,9 @@ public class EntryManager { * Apply metadata. * * @param username the username - * @param karma the karma - * @param entry the entry - * @param ignore the ignore + * @param karma the karma + * @param entry the entry + * @param ignore the ignore */ public void applyMetadata(String username, long karma, Entry entry, List ignore) { @@ -246,9 +383,9 @@ public class EntryManager { * Apply metadata. * * @param username the username - * @param karma the karma - * @param entries the entries - * @param ignore the ignore + * @param karma the karma + * @param entries the entries + * @param ignore the ignore */ public void applyMetadata(String username, long karma, List entries, List ignore) { @@ -295,6 +432,8 @@ public class EntryManager { public void delete(Entry entry) { commentManager.deleteByTarget(entry.getId()); voteManager.deleteByTarget(entry.getId(), Types.entry); + bookmarksManager.removeEntry(entry.getId()); + flagManager.deleteByTarget(entry.getId(), Types.entry); entryRepository.delete(entry); } @@ -315,7 +454,7 @@ public class EntryManager { /** * Gets the user points. * - * @param entryId the entry id + * @param entryId the entry id * @param username the username * @return the user points */ diff --git a/src/main/java/de/bstly/board/businesslogic/SettingsManager.java b/src/main/java/de/bstly/board/businesslogic/SettingsManager.java index 0c7f838..67d0c0d 100644 --- a/src/main/java/de/bstly/board/businesslogic/SettingsManager.java +++ b/src/main/java/de/bstly/board/businesslogic/SettingsManager.java @@ -16,6 +16,8 @@ public class SettingsManager { private double GRAVITY; @Value("${bstly.board.size:30}") private int SIZE; + @Value("${bstly.board.entry.changePeriod:1}") + private long ENTRY_CHANGE_PERIDO; @Value("${bstly.board.comment.changePeriod:1}") private long COMMENT_CHANGE_PERIDO; @Value("${bstly.board.unvoteThresh:10}") @@ -41,6 +43,15 @@ public class SettingsManager { return SIZE; } + /** + * Gets the entry delay. + * + * @return the entry delay + */ + public long getEntryDelay() { + return ENTRY_CHANGE_PERIDO; + } + /** * Gets the comment delay. * diff --git a/src/main/java/de/bstly/board/businesslogic/UserManager.java b/src/main/java/de/bstly/board/businesslogic/UserManager.java index 4099cdc..2dc7be0 100644 --- a/src/main/java/de/bstly/board/businesslogic/UserManager.java +++ b/src/main/java/de/bstly/board/businesslogic/UserManager.java @@ -107,6 +107,24 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet /* * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ + /* + * @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String) + */ /* * @see org.springframework.security.core.userdetails.UserDetailsService# * loadUserByUsername(java.lang.String) @@ -188,6 +206,24 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet /* * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + */ /* * @see org.springframework.beans.factory.SmartInitializingSingleton# * afterSingletonsInstantiated() diff --git a/src/main/java/de/bstly/board/controller/BaseController.java b/src/main/java/de/bstly/board/controller/BaseController.java index 6e6c34a..8e8d4e9 100644 --- a/src/main/java/de/bstly/board/controller/BaseController.java +++ b/src/main/java/de/bstly/board/controller/BaseController.java @@ -18,7 +18,7 @@ import de.bstly.board.security.LocalUserDetails; public class BaseController { @Autowired - private UserManager localUserManager; + private UserManager userManager; @Autowired private SettingsManager settingsManager; @@ -62,7 +62,7 @@ public class BaseController { protected int getPageSize() { String username = getCurrentUsername(); if (username != null) { - LocalUser localUser = localUserManager.getByUsername(username); + LocalUser localUser = userManager.getByUsername(username); if (localUser.getSettings() != null && localUser.getSettings().containsKey("pageSize")) { try { @@ -83,7 +83,7 @@ public class BaseController { protected double getGravity() { String username = getCurrentUsername(); if (username != null) { - LocalUser localUser = localUserManager.getByUsername(username); + LocalUser localUser = userManager.getByUsername(username); if (localUser.getSettings() != null && localUser.getSettings().containsKey("gravity")) { try { double gravity = Double.parseDouble(localUser.getSettings().get("gravity")); @@ -103,6 +103,36 @@ public class BaseController { return settingsManager.getGravity(); } + /** + * Gets the entry delay. + * + * @return the entry delay + */ + protected long getEntryDelay() { + String username = getCurrentUsername(); + if (username != null) { + LocalUser localUser = userManager.getByUsername(username); + if (localUser.getSettings() != null + && localUser.getSettings().containsKey("entryDelay")) { + try { + long entryDelay = Long.parseLong(localUser.getSettings().get("entryDelay")); + + if (entryDelay < 0) { + return 0; + } + + if (entryDelay > 15) { + return 15; + } + + return entryDelay; + } catch (Exception e) { + } + } + } + return settingsManager.getEntryDelay(); + } + /** * Gets the comment delay. * @@ -111,7 +141,7 @@ public class BaseController { protected long getCommentDelay() { String username = getCurrentUsername(); if (username != null) { - LocalUser localUser = localUserManager.getByUsername(username); + LocalUser localUser = userManager.getByUsername(username); if (localUser.getSettings() != null && localUser.getSettings().containsKey("commentDelay")) { try { diff --git a/src/main/java/de/bstly/board/controller/EntryController.java b/src/main/java/de/bstly/board/controller/EntryController.java index fc31081..04eb0fc 100644 --- a/src/main/java/de/bstly/board/controller/EntryController.java +++ b/src/main/java/de/bstly/board/controller/EntryController.java @@ -8,17 +8,17 @@ import java.io.InputStream; import java.net.URL; import java.net.URLDecoder; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.Scanner; -import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -38,7 +38,6 @@ import de.bstly.board.controller.validation.EntryValidator; import de.bstly.board.model.Entry; import de.bstly.board.model.EntryStatus; import de.bstly.board.model.FlaggedStatus; -import de.bstly.board.model.RankedEntry; import de.bstly.board.model.Types; import de.bstly.board.model.Vote; import de.bstly.board.model.VoteType; @@ -91,21 +90,15 @@ public class EntryController extends BaseController { gravityParameter = Optional.of(2.0); } - Page entries = entryManager.fetchByRanking(dateParameter.orElse(Instant.now()), + Page entries = entryManager.fetchByRanking(getCurrentUsername(), + dateParameter.orElse(null), FlaggedStatus.NORMAL, gravityParameter.orElse(getGravity()), pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); - Page transformed = new PageImpl( - entries.getContent().stream().map(rankedEntry -> { - Entry entry = Entry.fromRankedEntry(rankedEntry); - entry.getMetadata().put("points", rankedEntry.getPoints()); - return entry; - }).collect(Collectors.toList()), entries.getPageable(), entries.getTotalElements()); - List ignore = ignoreParameter.orElse(Lists.newArrayList()); entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), - transformed.getContent(), ignore); - return transformed; + entries.getContent(), ignore); + return entries; } /** @@ -132,8 +125,9 @@ public class EntryController extends BaseController { dateParameter = Optional.of(Instant.now()); } - Page entries = entryManager.fetchByDate(dateParameter.orElse(Instant.now()), - pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); + Page entries = entryManager.fetchByDate(getCurrentUsername(), + dateParameter.orElse(null), FlaggedStatus.NORMAL, pageParameter.orElse(0), + sizeParameter.orElse(settingsManager.getPageSize())); List ignore = ignoreParameter.orElse(Lists.newArrayList()); entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), entries.getContent(), ignore); @@ -166,19 +160,15 @@ public class EntryController extends BaseController { dateParameter = Optional.of(Instant.now()); } - Page entries = entryManager.fetchByComments( - dateParameter.orElse(Instant.now()), gravityParameter.orElse(getGravity()), - pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); - - Page transformed = new PageImpl( - entries.getContent().stream().map(rankedEntry -> Entry.fromRankedEntry(rankedEntry)) - .collect(Collectors.toList()), - entries.getPageable(), entries.getTotalElements()); + Page entries = entryManager.fetchByComments(getCurrentUsername(), + dateParameter.orElse(null), FlaggedStatus.NORMAL, + gravityParameter.orElse(getGravity()), pageParameter.orElse(0), + sizeParameter.orElse(settingsManager.getPageSize())); List ignore = ignoreParameter.orElse(Lists.newArrayList()); entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), - transformed.getContent(), ignore); - return transformed; + entries.getContent(), ignore); + return entries; } /** @@ -205,8 +195,9 @@ public class EntryController extends BaseController { dateParameter = Optional.of(Instant.now()); } - Page entries = entryManager.fetchByLastComment(dateParameter.orElse(Instant.now()), - pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); + Page entries = entryManager.fetchByLastComment(getCurrentUsername(), + dateParameter.orElse(null), FlaggedStatus.NORMAL, pageParameter.orElse(0), + sizeParameter.orElse(settingsManager.getPageSize())); List ignore = ignoreParameter.orElse(Lists.newArrayList()); entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), @@ -294,7 +285,7 @@ public class EntryController extends BaseController { HttpStatus.UNPROCESSABLE_ENTITY); } - entry.setCreated(Instant.now()); + entry.setCreated(Instant.now().plus(getEntryDelay(), ChronoUnit.MINUTES)); entry.setAuthor(getCurrentUsername()); entry.setEntryStatus(EntryStatus.NORMAL); entry.setFlaggedStatus(FlaggedStatus.NORMAL); @@ -316,6 +307,57 @@ public class EntryController extends BaseController { return entry; } + /** + * Update entry. + * + * @param entry the entry + * @param ignoreParameter the ignore parameter + * @return the entry + */ + @PreAuthorize("isAuthenticated()") + @PatchMapping + public Entry updateEntry(@RequestBody Entry entry, + @RequestParam("ignore") Optional> ignoreParameter) { + Entry orgEnry = entryManager.get(entry.getId()); + if (orgEnry == null || !orgEnry.getAuthor().equals(getCurrentUsername()) || orgEnry + .getCreated().plus(getEntryDelay(), ChronoUnit.MINUTES).isBefore(Instant.now())) { + throw new EntityResponseStatusException(HttpStatus.FORBIDDEN); + } + + RequestBodyErrors bindingResult = new RequestBodyErrors(entry); + entryValidator.validate(entry, bindingResult); + + if (bindingResult.hasErrors()) { + throw new EntityResponseStatusException(bindingResult.getAllErrors(), + HttpStatus.UNPROCESSABLE_ENTITY); + } + + orgEnry.setUrl(entry.getUrl()); + orgEnry.setTitle(entry.getTitle().trim()); + orgEnry.setText(entry.getText().trim()); + orgEnry = entryManager.save(orgEnry); + + List ignore = ignoreParameter.orElse(Lists.newArrayList()); + entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), + entry, ignore); + return entry; + } + + /** + * Detele entry. + * + * @param id the id + */ + public void deteleEntry(@PathVariable("id") Long id) { + Entry orgEntry = entryManager.get(id); + if (orgEntry == null || !orgEntry.getAuthor().equals(getCurrentUsername()) || orgEntry + .getCreated().plus(getEntryDelay(), ChronoUnit.MINUTES).isBefore(Instant.now())) { + throw new EntityResponseStatusException(HttpStatus.FORBIDDEN); + } + + entryManager.delete(orgEntry); + } + /** * Gets the title. * diff --git a/src/main/java/de/bstly/board/controller/SettingsController.java b/src/main/java/de/bstly/board/controller/SettingsController.java index 4a580e5..ec31c8b 100644 --- a/src/main/java/de/bstly/board/controller/SettingsController.java +++ b/src/main/java/de/bstly/board/controller/SettingsController.java @@ -34,9 +34,11 @@ public class SettingsController extends BaseController { Map settings = Maps.newHashMap(); settings.put("gravity", getGravity()); settings.put("pageSize", getPageSize()); + settings.put("entryDelay", getEntryDelay()); settings.put("commentDelay", getCommentDelay()); settings.put("defaultGravity", settingsManager.getGravity()); settings.put("defaultPageSize", settingsManager.getPageSize()); + settings.put("defaultEntryDelay", settingsManager.getEntryDelay()); settings.put("defaultCommentDelay", settingsManager.getCommentDelay()); return settings; } diff --git a/src/main/java/de/bstly/board/model/Entry.java b/src/main/java/de/bstly/board/model/Entry.java index fba9ec6..9a7b39f 100644 --- a/src/main/java/de/bstly/board/model/Entry.java +++ b/src/main/java/de/bstly/board/model/Entry.java @@ -57,6 +57,8 @@ public class Entry { @Transient private Double ranking; @Transient + private Long points; + @Transient private Map metadata; /** @@ -239,6 +241,24 @@ public class Entry { this.ranking = ranking; } + /** + * Gets the points. + * + * @return the points + */ + public Long getPoints() { + return points; + } + + /** + * Sets the points. + * + * @param points the new points + */ + public void setPoints(Long points) { + this.points = points; + } + /** * Gets the metadata. * @@ -260,23 +280,4 @@ public class Entry { this.metadata = metadata; } - /** - * From ranked entry. - * - * @param rankedEntry the ranked entry - * @return the entry - */ - public static Entry fromRankedEntry(RankedEntry rankedEntry) { - Entry entry = new Entry(); - entry.setId(rankedEntry.getId()); - entry.setAuthor(rankedEntry.getAuthor()); - entry.setCreated(rankedEntry.getCreated()); - entry.setEntryType(rankedEntry.getEntry_Type()); - entry.setUrl(rankedEntry.getUrl()); - entry.setTitle(rankedEntry.getTitle()); - entry.setText(rankedEntry.getText()); - entry.setRanking(rankedEntry.getRanking()); - return entry; - } - } diff --git a/src/main/java/de/bstly/board/model/RankedEntry.java b/src/main/java/de/bstly/board/model/RankedEntry.java deleted file mode 100644 index 581f973..0000000 --- a/src/main/java/de/bstly/board/model/RankedEntry.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * - */ -package de.bstly.board.model; - -import java.time.Instant; - - -/** - * The Interface RankedEntry. - */ -public interface RankedEntry { - - /** - * Gets the id. - * - * @return the id - */ - Long getId(); - - /** - * Gets the author. - * - * @return the author - */ - String getAuthor(); - - /** - * Gets the created. - * - * @return the created - */ - Instant getCreated(); - - /** - * Gets the entry type. - * - * @return the entry type - */ - EntryType getEntry_Type(); - - /** - * Gets the url. - * - * @return the url - */ - String getUrl(); - - /** - * Gets the title. - * - * @return the title - */ - String getTitle(); - - /** - * Gets the text. - * - * @return the text - */ - String getText(); - - /** - * Gets the ranking. - * - * @return the ranking - */ - Double getRanking(); - - /** - * Gets the points. - * - * @return the points - */ - Long getPoints(); -} diff --git a/src/main/java/de/bstly/board/repository/EntryRepository.java b/src/main/java/de/bstly/board/repository/EntryRepository.java index bc9c3d3..805fd28 100644 --- a/src/main/java/de/bstly/board/repository/EntryRepository.java +++ b/src/main/java/de/bstly/board/repository/EntryRepository.java @@ -3,18 +3,11 @@ */ package de.bstly.board.repository; -import java.time.Instant; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; import org.springframework.data.querydsl.QuerydslPredicateExecutor; -import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import de.bstly.board.model.Entry; -import de.bstly.board.model.RankedEntry; /** * The Interface EntryRepository. @@ -23,60 +16,4 @@ import de.bstly.board.model.RankedEntry; public interface EntryRepository extends JpaRepository, QuerydslPredicateExecutor { - static final String UPVOTES_QUERY = "SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 1 GROUP BY upvote.target"; - - static final String DOWNVOTES_QUERY = "SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 AND downvote.target_type = 1 GROUP BY downvote.target"; - - static final String COMMENTS_QUERY = "SELECT comment.target,MAX(comment.created) as last,COUNT(comment.id) AS count FROM comments as comment WHERE comment.flagged_status = 'NORMAL' GROUP BY comment.target"; - - static final String RANK_CALCULATION_QUERY = "SELECT entry.*, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) as points, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / IF(:gravity > 0, POW(TIMESTAMPDIFF(HOUR, entry.created, :before)+2,:gravity), 1) AS ranking FROM entries AS entry LEFT JOIN (" - + UPVOTES_QUERY - + ") AS upvote ON upvote.target = entry.id LEFT JOIN (" - + DOWNVOTES_QUERY - + ") AS downvote ON downvote.target = entry.id WHERE entry.created < :before AND entry.flagged_status = 'NORMAL' ORDER BY ranking DESC, entry.created DESC"; - - static final String COMMENT_CALCULATION_QUERY = "SELECT entry.*, IFNULL(comment.count,0) as comments, IFNULL(comment.count,0) / IF(:gravity > 0, POW(TIMESTAMPDIFF(HOUR, comment.last, :before)+2,:gravity), 1) AS ranking FROM entries AS entry LEFT JOIN (" - + COMMENTS_QUERY - + ") AS comment ON comment.target = entry.id WHERE entry.created < :before AND entry.flagged_status = 'NORMAL' ORDER BY ranking DESC, entry.created DESC"; - - static final String LAST_COMMENT_QUERY = "SELECT entry.* FROM entries AS entry LEFT JOIN (" - + COMMENTS_QUERY - + ") AS comment ON comment.target = entry.id WHERE entry.created < :before AND entry.flagged_status = 'NORMAL' ORDER BY comment.last DESC, entry.created DESC"; - - static final String COUNT_QUERY = "SELECT count(*) FROM entries as entry WHERE entry.created < :before AND entry.flagged_status = 'NORMAL'"; - - /** - * Find all by ranking. - * - * @param before the before - * @param gravity the gravity - * @param pageable the pageable - * @return the page - */ - @Query(value = RANK_CALCULATION_QUERY, countQuery = COUNT_QUERY, nativeQuery = true) - Page findAllByRanking(@Param("before") Instant before, - @Param("gravity") double gravity, Pageable pageable); - - /** - * Find all by comments. - * - * @param before the before - * @param gravity the gravity - * @param pageable the pageable - * @return the page - */ - @Query(value = COMMENT_CALCULATION_QUERY, countQuery = COUNT_QUERY, nativeQuery = true) - Page findAllByComments(@Param("before") Instant before, - @Param("gravity") double gravity, Pageable pageable); - - /** - * Find all by last comment. - * - * @param before the before - * @param pageable the pageable - * @return the page - */ - @Query(value = LAST_COMMENT_QUERY, countQuery = COUNT_QUERY, nativeQuery = true) - Page findAllByLastComment(@Param("before") Instant before, Pageable pageable); - } diff --git a/src/main/java/de/bstly/board/security/SecurityConfig.java b/src/main/java/de/bstly/board/security/SecurityConfig.java index cd9edd4..fb31934 100755 --- a/src/main/java/de/bstly/board/security/SecurityConfig.java +++ b/src/main/java/de/bstly/board/security/SecurityConfig.java @@ -50,6 +50,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${loginTargetUrl:/}") private String loginTargetUrl; + /* + * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity) + */ /* * @see org.springframework.security.config.annotation.web.configuration. * WebSecurityConfigurerAdapter#configure(org.springframework.security.config. @@ -126,6 +129,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { return rememberMeServices; } + /** + * Cors configuration source. + * + * @return the cors configuration source + */ @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration();