added entry edit

This commit is contained in:
_Bastler 2021-11-21 16:43:19 +01:00
parent 2a646b0ece
commit dcdb140f67
13 changed files with 389 additions and 245 deletions

View File

@ -10,7 +10,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version> <java.version>11</java.version>
<revision>1.0.0</revision> <revision>1.0.1</revision>
</properties> </properties>
<parent> <parent>

View File

@ -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);
}
}
} }

View File

@ -283,6 +283,7 @@ public class CommentManager {
} }
voteManager.deleteByTarget(comment.getId(), Types.comment); voteManager.deleteByTarget(comment.getId(), Types.comment);
flagManager.deleteByTarget(comment.getId(), Types.comment);
commentRepository.delete(comment); commentRepository.delete(comment);
} }

View File

@ -3,9 +3,13 @@
*/ */
package de.bstly.board.businesslogic; package de.bstly.board.businesslogic;
import java.math.BigInteger;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; 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.Bookmarks;
import de.bstly.board.model.Entry; 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.QEntry;
import de.bstly.board.model.QFlag; import de.bstly.board.model.QFlag;
import de.bstly.board.model.QVote; import de.bstly.board.model.QVote;
import de.bstly.board.model.RankedEntry;
import de.bstly.board.model.Types; import de.bstly.board.model.Types;
import de.bstly.board.model.VoteType; import de.bstly.board.model.VoteType;
import de.bstly.board.repository.EntryRepository; import de.bstly.board.repository.EntryRepository;
@ -53,61 +56,195 @@ public class EntryManager {
private FlagManager flagManager; private FlagManager flagManager;
@Autowired @Autowired
private JPAQueryFactory jpaQueryFactory; private JPAQueryFactory jpaQueryFactory;
@Autowired
private EntityManager em;
private QEntry qEntry = QEntry.entry; private QEntry qEntry = QEntry.entry;
private QVote qVote = QVote.vote; private QVote qVote = QVote.vote;
private QFlag qFlag = QFlag.flag; 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. * Fetch by ranking.
* *
* @param date the date * @param username the username
* @param gravity the gravity * @param date the date
* @param page the page * @param flaggedStatus the flagged status
* @param size the size * @param gravity the gravity
* @param page the page
* @param size the size
* @return the page * @return the page
*/ */
public Page<RankedEntry> fetchByRanking(Instant date, double gravity, int page, int size) { public Page<Entry> fetchByRanking(String username, Instant date, FlaggedStatus flaggedStatus,
return entryRepository.findAllByRanking(date, gravity, PageRequest.of(page, size)); double gravity, int page, int size) {
} Query query = createEntryQuery(RANK_CALCULATION_QUERY, username, date, flaggedStatus);
query.setParameter("gravity", gravity);
/** query.setFirstResult((page) * size);
* Fetch by comments. query.setMaxResults(size);
* @SuppressWarnings("unchecked")
* @param date the date List<Entry> list = query.getResultList();
* @param gravity the gravity Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus);
* @param page the page long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue();
* @param size the size return new PageImpl<Entry>(list, PageRequest.of(page, size), countResult);
* @return the page
*/
public Page<RankedEntry> 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<Entry> fetchByLastComment(Instant date, int page, int size) {
return entryRepository.findAllByLastComment(date, PageRequest.of(page, size));
} }
/** /**
* Fetch by date. * Fetch by date.
* *
* @param date the date * @param username the username
* @param page the page * @param date the date
* @param size the size * @param flaggedStatus the flagged status
* @param page the page
* @param size the size
* @return the page * @return the page
*/ */
public Page<Entry> fetchByDate(Instant date, int page, int size) { public Page<Entry> fetchByDate(String username, Instant date, FlaggedStatus flaggedStatus,
return entryRepository.findAll( int page, int size) {
qEntry.created.before(date).and(qEntry.entryStatus.eq(EntryStatus.NORMAL)), Query query = createEntryQuery(DATE_QUERY, username, date, flaggedStatus);
PageRequest.of(page, size, Sort.by(Order.desc("created")))); query.setFirstResult((page) * size);
query.setMaxResults(size);
@SuppressWarnings("unchecked")
List<Entry> list = query.getResultList();
Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus);
long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue();
return new PageImpl<Entry>(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<Entry> 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<Entry> list = query.getResultList();
Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus);
long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue();
return new PageImpl<Entry>(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<Entry> 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<Entry> list = query.getResultList();
Query queryTotal = createCountQuery(COUNT_QUERY, username, date, flaggedStatus);
long countResult = ((BigInteger) queryTotal.getSingleResult()).longValue();
return new PageImpl<Entry>(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 page the page
* @param size the size * @param size the size
* @param asc the asc * @param asc the asc
* @return the page * @return the page
*/ */
public Page<Entry> fetchFlagged(int page, int size, boolean asc) { public Page<Entry> fetchFlagged(int page, int size, boolean asc) {
@ -134,10 +271,10 @@ public class EntryManager {
* Fetch by user. * Fetch by user.
* *
* @param username the username * @param username the username
* @param date the date * @param date the date
* @param page the page * @param page the page
* @param size the size * @param size the size
* @param asc the asc * @param asc the asc
* @return the page * @return the page
*/ */
public Page<Entry> fetchByUser(String username, Instant date, int page, int size, boolean asc) { public Page<Entry> fetchByUser(String username, Instant date, int page, int size, boolean asc) {
@ -151,8 +288,8 @@ public class EntryManager {
* Fetch by bookmarks. * Fetch by bookmarks.
* *
* @param username the username * @param username the username
* @param page the page * @param page the page
* @param size the size * @param size the size
* @return the page * @return the page
*/ */
public Page<Entry> fetchByBookmarks(String username, int page, int size) { public Page<Entry> fetchByBookmarks(String username, int page, int size) {
@ -170,9 +307,9 @@ public class EntryManager {
* Apply metadata. * Apply metadata.
* *
* @param username the username * @param username the username
* @param karma the karma * @param karma the karma
* @param entry the entry * @param entry the entry
* @param ignore the ignore * @param ignore the ignore
*/ */
public void applyMetadata(String username, long karma, Entry entry, List<String> ignore) { public void applyMetadata(String username, long karma, Entry entry, List<String> ignore) {
@ -246,9 +383,9 @@ public class EntryManager {
* Apply metadata. * Apply metadata.
* *
* @param username the username * @param username the username
* @param karma the karma * @param karma the karma
* @param entries the entries * @param entries the entries
* @param ignore the ignore * @param ignore the ignore
*/ */
public void applyMetadata(String username, long karma, List<Entry> entries, public void applyMetadata(String username, long karma, List<Entry> entries,
List<String> ignore) { List<String> ignore) {
@ -295,6 +432,8 @@ public class EntryManager {
public void delete(Entry entry) { public void delete(Entry entry) {
commentManager.deleteByTarget(entry.getId()); commentManager.deleteByTarget(entry.getId());
voteManager.deleteByTarget(entry.getId(), Types.entry); voteManager.deleteByTarget(entry.getId(), Types.entry);
bookmarksManager.removeEntry(entry.getId());
flagManager.deleteByTarget(entry.getId(), Types.entry);
entryRepository.delete(entry); entryRepository.delete(entry);
} }
@ -315,7 +454,7 @@ public class EntryManager {
/** /**
* Gets the user points. * Gets the user points.
* *
* @param entryId the entry id * @param entryId the entry id
* @param username the username * @param username the username
* @return the user points * @return the user points
*/ */

View File

@ -16,6 +16,8 @@ public class SettingsManager {
private double GRAVITY; private double GRAVITY;
@Value("${bstly.board.size:30}") @Value("${bstly.board.size:30}")
private int SIZE; private int SIZE;
@Value("${bstly.board.entry.changePeriod:1}")
private long ENTRY_CHANGE_PERIDO;
@Value("${bstly.board.comment.changePeriod:1}") @Value("${bstly.board.comment.changePeriod:1}")
private long COMMENT_CHANGE_PERIDO; private long COMMENT_CHANGE_PERIDO;
@Value("${bstly.board.unvoteThresh:10}") @Value("${bstly.board.unvoteThresh:10}")
@ -41,6 +43,15 @@ public class SettingsManager {
return SIZE; return SIZE;
} }
/**
* Gets the entry delay.
*
* @return the entry delay
*/
public long getEntryDelay() {
return ENTRY_CHANGE_PERIDO;
}
/** /**
* Gets the comment delay. * Gets the comment delay.
* *

View File

@ -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)
*/
/* /*
* @see org.springframework.security.core.userdetails.UserDetailsService# * @see org.springframework.security.core.userdetails.UserDetailsService#
* loadUserByUsername(java.lang.String) * 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()
*/
/* /*
* @see org.springframework.beans.factory.SmartInitializingSingleton# * @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated() * afterSingletonsInstantiated()

View File

@ -18,7 +18,7 @@ import de.bstly.board.security.LocalUserDetails;
public class BaseController { public class BaseController {
@Autowired @Autowired
private UserManager localUserManager; private UserManager userManager;
@Autowired @Autowired
private SettingsManager settingsManager; private SettingsManager settingsManager;
@ -62,7 +62,7 @@ public class BaseController {
protected int getPageSize() { protected int getPageSize() {
String username = getCurrentUsername(); String username = getCurrentUsername();
if (username != null) { if (username != null) {
LocalUser localUser = localUserManager.getByUsername(username); LocalUser localUser = userManager.getByUsername(username);
if (localUser.getSettings() != null if (localUser.getSettings() != null
&& localUser.getSettings().containsKey("pageSize")) { && localUser.getSettings().containsKey("pageSize")) {
try { try {
@ -83,7 +83,7 @@ public class BaseController {
protected double getGravity() { protected double getGravity() {
String username = getCurrentUsername(); String username = getCurrentUsername();
if (username != null) { if (username != null) {
LocalUser localUser = localUserManager.getByUsername(username); LocalUser localUser = userManager.getByUsername(username);
if (localUser.getSettings() != null && localUser.getSettings().containsKey("gravity")) { if (localUser.getSettings() != null && localUser.getSettings().containsKey("gravity")) {
try { try {
double gravity = Double.parseDouble(localUser.getSettings().get("gravity")); double gravity = Double.parseDouble(localUser.getSettings().get("gravity"));
@ -103,6 +103,36 @@ public class BaseController {
return settingsManager.getGravity(); 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. * Gets the comment delay.
* *
@ -111,7 +141,7 @@ public class BaseController {
protected long getCommentDelay() { protected long getCommentDelay() {
String username = getCurrentUsername(); String username = getCurrentUsername();
if (username != null) { if (username != null) {
LocalUser localUser = localUserManager.getByUsername(username); LocalUser localUser = userManager.getByUsername(username);
if (localUser.getSettings() != null if (localUser.getSettings() != null
&& localUser.getSettings().containsKey("commentDelay")) { && localUser.getSettings().containsKey("commentDelay")) {
try { try {

View File

@ -8,17 +8,17 @@ import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.time.Instant; import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Scanner; import java.util.Scanner;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping; 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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; 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.Entry;
import de.bstly.board.model.EntryStatus; import de.bstly.board.model.EntryStatus;
import de.bstly.board.model.FlaggedStatus; import de.bstly.board.model.FlaggedStatus;
import de.bstly.board.model.RankedEntry;
import de.bstly.board.model.Types; import de.bstly.board.model.Types;
import de.bstly.board.model.Vote; import de.bstly.board.model.Vote;
import de.bstly.board.model.VoteType; import de.bstly.board.model.VoteType;
@ -91,21 +90,15 @@ public class EntryController extends BaseController {
gravityParameter = Optional.of(2.0); gravityParameter = Optional.of(2.0);
} }
Page<RankedEntry> entries = entryManager.fetchByRanking(dateParameter.orElse(Instant.now()), Page<Entry> entries = entryManager.fetchByRanking(getCurrentUsername(),
dateParameter.orElse(null), FlaggedStatus.NORMAL,
gravityParameter.orElse(getGravity()), pageParameter.orElse(0), gravityParameter.orElse(getGravity()), pageParameter.orElse(0),
sizeParameter.orElse(settingsManager.getPageSize())); sizeParameter.orElse(settingsManager.getPageSize()));
Page<Entry> transformed = new PageImpl<Entry>(
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<String> ignore = ignoreParameter.orElse(Lists.newArrayList()); List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
transformed.getContent(), ignore); entries.getContent(), ignore);
return transformed; return entries;
} }
/** /**
@ -132,8 +125,9 @@ public class EntryController extends BaseController {
dateParameter = Optional.of(Instant.now()); dateParameter = Optional.of(Instant.now());
} }
Page<Entry> entries = entryManager.fetchByDate(dateParameter.orElse(Instant.now()), Page<Entry> entries = entryManager.fetchByDate(getCurrentUsername(),
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); dateParameter.orElse(null), FlaggedStatus.NORMAL, pageParameter.orElse(0),
sizeParameter.orElse(settingsManager.getPageSize()));
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList()); List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
entries.getContent(), ignore); entries.getContent(), ignore);
@ -166,19 +160,15 @@ public class EntryController extends BaseController {
dateParameter = Optional.of(Instant.now()); dateParameter = Optional.of(Instant.now());
} }
Page<RankedEntry> entries = entryManager.fetchByComments( Page<Entry> entries = entryManager.fetchByComments(getCurrentUsername(),
dateParameter.orElse(Instant.now()), gravityParameter.orElse(getGravity()), dateParameter.orElse(null), FlaggedStatus.NORMAL,
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); gravityParameter.orElse(getGravity()), pageParameter.orElse(0),
sizeParameter.orElse(settingsManager.getPageSize()));
Page<Entry> transformed = new PageImpl<Entry>(
entries.getContent().stream().map(rankedEntry -> Entry.fromRankedEntry(rankedEntry))
.collect(Collectors.toList()),
entries.getPageable(), entries.getTotalElements());
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList()); List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
transformed.getContent(), ignore); entries.getContent(), ignore);
return transformed; return entries;
} }
/** /**
@ -205,8 +195,9 @@ public class EntryController extends BaseController {
dateParameter = Optional.of(Instant.now()); dateParameter = Optional.of(Instant.now());
} }
Page<Entry> entries = entryManager.fetchByLastComment(dateParameter.orElse(Instant.now()), Page<Entry> entries = entryManager.fetchByLastComment(getCurrentUsername(),
pageParameter.orElse(0), sizeParameter.orElse(settingsManager.getPageSize())); dateParameter.orElse(null), FlaggedStatus.NORMAL, pageParameter.orElse(0),
sizeParameter.orElse(settingsManager.getPageSize()));
List<String> ignore = ignoreParameter.orElse(Lists.newArrayList()); List<String> ignore = ignoreParameter.orElse(Lists.newArrayList());
entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()), entryManager.applyMetadata(getCurrentUsername(), userManager.getKarma(getCurrentUsername()),
@ -294,7 +285,7 @@ public class EntryController extends BaseController {
HttpStatus.UNPROCESSABLE_ENTITY); HttpStatus.UNPROCESSABLE_ENTITY);
} }
entry.setCreated(Instant.now()); entry.setCreated(Instant.now().plus(getEntryDelay(), ChronoUnit.MINUTES));
entry.setAuthor(getCurrentUsername()); entry.setAuthor(getCurrentUsername());
entry.setEntryStatus(EntryStatus.NORMAL); entry.setEntryStatus(EntryStatus.NORMAL);
entry.setFlaggedStatus(FlaggedStatus.NORMAL); entry.setFlaggedStatus(FlaggedStatus.NORMAL);
@ -316,6 +307,57 @@ public class EntryController extends BaseController {
return entry; 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<List<String>> 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<String> 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. * Gets the title.
* *

View File

@ -34,9 +34,11 @@ public class SettingsController extends BaseController {
Map<String, Object> settings = Maps.newHashMap(); Map<String, Object> settings = Maps.newHashMap();
settings.put("gravity", getGravity()); settings.put("gravity", getGravity());
settings.put("pageSize", getPageSize()); settings.put("pageSize", getPageSize());
settings.put("entryDelay", getEntryDelay());
settings.put("commentDelay", getCommentDelay()); settings.put("commentDelay", getCommentDelay());
settings.put("defaultGravity", settingsManager.getGravity()); settings.put("defaultGravity", settingsManager.getGravity());
settings.put("defaultPageSize", settingsManager.getPageSize()); settings.put("defaultPageSize", settingsManager.getPageSize());
settings.put("defaultEntryDelay", settingsManager.getEntryDelay());
settings.put("defaultCommentDelay", settingsManager.getCommentDelay()); settings.put("defaultCommentDelay", settingsManager.getCommentDelay());
return settings; return settings;
} }

View File

@ -57,6 +57,8 @@ public class Entry {
@Transient @Transient
private Double ranking; private Double ranking;
@Transient @Transient
private Long points;
@Transient
private Map<String, Object> metadata; private Map<String, Object> metadata;
/** /**
@ -239,6 +241,24 @@ public class Entry {
this.ranking = ranking; 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. * Gets the metadata.
* *
@ -260,23 +280,4 @@ public class Entry {
this.metadata = metadata; 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;
}
} }

View File

@ -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();
}

View File

@ -3,18 +3,11 @@
*/ */
package de.bstly.board.repository; 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.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor; import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import de.bstly.board.model.Entry; import de.bstly.board.model.Entry;
import de.bstly.board.model.RankedEntry;
/** /**
* The Interface EntryRepository. * The Interface EntryRepository.
@ -23,60 +16,4 @@ import de.bstly.board.model.RankedEntry;
public interface EntryRepository public interface EntryRepository
extends JpaRepository<Entry, Long>, QuerydslPredicateExecutor<Entry> { extends JpaRepository<Entry, Long>, QuerydslPredicateExecutor<Entry> {
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<RankedEntry> 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<RankedEntry> 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<Entry> findAllByLastComment(@Param("before") Instant before, Pageable pageable);
} }

View File

@ -50,6 +50,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${loginTargetUrl:/}") @Value("${loginTargetUrl:/}")
private String 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. * @see org.springframework.security.config.annotation.web.configuration.
* WebSecurityConfigurerAdapter#configure(org.springframework.security.config. * WebSecurityConfigurerAdapter#configure(org.springframework.security.config.
@ -126,6 +129,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
return rememberMeServices; return rememberMeServices;
} }
/**
* Cors configuration source.
*
* @return the cors configuration source
*/
@Bean @Bean
public CorsConfigurationSource corsConfigurationSource() { public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration(); CorsConfiguration configuration = new CorsConfiguration();