improvements + bookmarks

This commit is contained in:
_Bastler 2021-10-04 13:02:40 +02:00
parent 1fc18fdeb2
commit d3f6c86db6
48 changed files with 1542 additions and 432 deletions

View File

@ -8,15 +8,15 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
/**
*
* @author spring-cachet-monitoring@champonthis.de
*
* The Class Application.
*/
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
/**
* @param args
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {
SpringApplication.run(Application.class, args);

View File

@ -13,8 +13,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import com.querydsl.jpa.impl.JPAQueryFactory;
/**
* @author monitoring@bstly.de
*
* The Class JPAConfig.
*/
@Configuration
@EnableJpaAuditing()
@ -23,6 +22,11 @@ public class JPAConfig {
@Autowired
private EntityManager em;
/**
* Jpa query factory.
*
* @return the JPA query factory
*/
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);

View File

@ -12,17 +12,22 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
/**
* @author monitoring@bstly.de
*
* The Class MessageSourceConfig.
*/
@Configuration
public class MessageSourceConfig {
@Value("${bstly.board.title:bstlboard}")
private String title;
@Value("${bstly.board.url:http://localhost:8080}")
private String baseUrl;
/**
* Message source.
*
* @return the message source
*/
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();

View File

@ -0,0 +1,97 @@
/**
*
*/
package de.bstly.board.businesslogic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import com.google.common.collect.Lists;
import de.bstly.board.model.Bookmarks;
import de.bstly.board.model.QBookmarks;
import de.bstly.board.repository.BookmarksRepository;
import de.bstly.board.repository.EntryRepository;
import de.bstly.board.repository.LocalUserRepository;
/**
* The Class BookmarksManager.
*/
@Component
public class BookmarksManager {
@Autowired
private BookmarksRepository bookmarksRepository;
@Autowired
private EntryRepository entryRepository;
@Autowired
private LocalUserRepository localUserRepository;
private QBookmarks qBookmarks = QBookmarks.bookmarks;
/**
* Gets the.
*
* @param username the username
* @return the bookmarks
*/
public Bookmarks get(String username) {
return bookmarksRepository.findById(username).orElse(new Bookmarks(username));
}
/**
* Checks for entry.
*
* @param username the username
* @param entryId the entry id
* @return true, if successful
*/
public boolean hasEntry(String username, Long entryId) {
return bookmarksRepository
.exists(qBookmarks.username.eq(username).and(qBookmarks.entries.contains(entryId)));
}
/**
* Adds the entry.
*
* @param username the username
* @param entryId the entry id
*/
public void addEntry(String username, Long entryId) {
Assert.isTrue(entryRepository.existsById(entryId), "Invalid entryid");
Assert.isTrue(localUserRepository.existsById(username), "Invalid username");
Bookmarks bookmarks = get(username);
if (bookmarks.getEntries() == null) {
bookmarks.setEntries(Lists.newArrayList());
}
if (!hasEntry(username, entryId)) {
bookmarks.getEntries().add(entryId);
bookmarksRepository.save(bookmarks);
}
}
/**
* Removes the entry.
*
* @param username the username
* @param entryId the entry id
*/
public void removeEntry(String username, Long entryId) {
Assert.isTrue(entryRepository.existsById(entryId), "Invalid entryid");
Assert.isTrue(localUserRepository.existsById(username), "Invalid username");
Bookmarks bookmarks = get(username);
if (bookmarks.getEntries() == null) {
bookmarks.setEntries(Lists.newArrayList());
}
if (hasEntry(username, entryId)) {
bookmarks.getEntries().remove(entryId);
bookmarksRepository.save(bookmarks);
}
}
}

View File

@ -22,28 +22,34 @@ import de.bstly.board.repository.CommentRepository;
import de.bstly.board.repository.VoteRepository;
/**
* @author Lurkars
*
* The Class CommentManager.
*/
@Component
public class CommentManager {
@Autowired
private CommentRepository commentRepository;
@Autowired
private VoteRepository voteRepository;
@Autowired
private VoteManager voteManager;
private QComment qComment = QComment.comment;
private QVote qVote = QVote.vote;
/**
*
* @param parent
* @param target
* @param page
* @param size
* @return
* Fetch by ranking.
*
* @param target the target
* @param parent the parent
* @param date the date
* @param gravity the gravity
* @param page the page
* @param size the size
* @return the page
*/
public Page<Comment> fetchByRanking(Long target, Long parent, Instant date, double gravity,
@ -58,11 +64,14 @@ public class CommentManager {
}
/**
*
* @param page
* @param size
* @param order
* @return
* Fetch by date.
*
* @param target the target
* @param parent the parent
* @param date the date
* @param page the page
* @param size the size
* @return the page
*/
public Page<Comment> fetchByDate(Long target, Long parent, Instant date, int page, int size) {
if (parent == null) {
@ -79,10 +88,11 @@ public class CommentManager {
}
/**
*
* @param target
* @param parent
* @return
* Count.
*
* @param target the target
* @param parent the parent
* @return the long
*/
public Long count(Long target, Long parent) {
if (parent == null) {
@ -93,18 +103,20 @@ public class CommentManager {
}
/**
*
* @param target
* @return
* Count.
*
* @param target the target
* @return the long
*/
public Long count(Long target) {
return commentRepository.count(qComment.target.eq(target));
}
/**
*
* @param username
* @param comment
* Apply metadata.
*
* @param username the username
* @param comment the comment
*/
public void applyMetadata(String username, Comment comment) {
if (!comment.getMetadata().containsKey("comments")) {
@ -114,21 +126,21 @@ public class CommentManager {
comment.getMetadata().put("points",
voteManager.getPoints(comment.getId(), Types.comment));
}
if (!comment.getMetadata().containsKey("upvoted")) {
comment.getMetadata().put("upvoted",
voteRepository.exists(qVote.target.eq(comment.getId())
.and(qVote.targetType.eq(Types.comment)).and(qVote.type.eq(VoteType.up))
.and(qVote.author.eq(username))));
}
if (!comment.getMetadata().containsKey("downvoted")) {
comment.getMetadata().put("downvoted",
voteRepository.exists(qVote.target.eq(comment.getId())
.and(qVote.targetType.eq(Types.comment))
.and(qVote.type.eq(VoteType.down)).and(qVote.author.eq(username))));
}
if (!comment.getMetadata().containsKey("unvote")) {
comment.getMetadata().put("unvote",
voteRepository.exists(
@ -138,8 +150,10 @@ public class CommentManager {
}
/**
*
* @param entries
* Apply metadata.
*
* @param username the username
* @param entries the entries
*/
public void applyMetadata(String username, List<Comment> entries) {
for (Comment comment : entries) {
@ -148,33 +162,40 @@ public class CommentManager {
}
/**
* @param id
* @return
* Exists.
*
* @param id the id
* @return true, if successful
*/
public boolean exists(Long id) {
return commentRepository.existsById(id);
}
/**
* @param id
* @return
* Gets the.
*
* @param id the id
* @return the comment
*/
public Comment get(Long id) {
return commentRepository.findById(id).orElse(null);
}
/**
* @param comment
* @return
* Save.
*
* @param comment the comment
* @return the comment
*/
public Comment save(Comment comment) {
return commentRepository.save(comment);
}
/**
*
* @param commentId
* @return
* Gets the points.
*
* @param commentId the comment id
* @return the points
*/
public long getPoints(Long commentId) {
long upvotes = voteRepository.count(qVote.targetType.eq(Types.comment)
@ -185,8 +206,9 @@ public class CommentManager {
}
/**
*
* @param comment
* Delete.
*
* @param comment the comment
*/
public void delete(Comment comment) {
for (Comment subcomment : commentRepository.findAll(qComment.parent.eq(comment.getId()))) {
@ -199,8 +221,9 @@ public class CommentManager {
}
/**
*
* @param target
* Delete by target.
*
* @param target the target
*/
public void deleteByTarget(Long target) {
for (Comment comment : commentRepository.findAll(qComment.target.eq(target))) {

View File

@ -14,6 +14,9 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.stereotype.Component;
import com.google.common.collect.Lists;
import de.bstly.board.model.Bookmarks;
import de.bstly.board.model.Entry;
import de.bstly.board.model.QEntry;
import de.bstly.board.model.QVote;
@ -24,8 +27,7 @@ import de.bstly.board.repository.EntryRepository;
import de.bstly.board.repository.VoteRepository;
/**
* @author Lurkars
*
* The Class EntryManager.
*/
@Component
public class EntryManager {
@ -38,29 +40,39 @@ public class EntryManager {
private VoteManager voteManager;
@Autowired
private VoteRepository voteRepository;
@Autowired
private BookmarksManager bookmarksManager;
private QEntry qEntry = QEntry.entry;
private QVote qVote = QVote.vote;
@Value("${bstly.board.ranking.gravity:1.8}")
private double GRAVITY;
/**
*
* @param page
* @param size
* @return
* Direct fetch by ranking.
*
* @param date the date
* @param gravity the gravity
* @param page the page
* @param size the size
* @return the page
*/
public Page<Entry> fetchByRanking(int page, int size) {
return entryRepository.findAll(
PageRequest.of(page, size, Sort.by(Order.desc("ranking"), Order.desc("created"))));
public Page<RankedEntry> fetchByRanking(Instant date, double gravity, int page,
int size) {
return entryRepository.findAllByRanking(date, gravity, PageRequest.of(page, size));
}
/**
*
* @param page
* @param size
* @param order
* @return
* Fetch by date.
*
* @param date the date
* @param page the page
* @param size the size
* @return the page
*/
public Page<Entry> fetchByDate(Instant date, int page, int size) {
return entryRepository.findAll(qEntry.created.before(date),
@ -68,53 +80,69 @@ public class EntryManager {
}
/**
*
* @param page
* @param size
* @return
* Gets the entries.
*
* @param username the username
* @param page the page
* @param size the size
* @return the entries
*/
public Page<RankedEntry> directFetchByRanking(Instant date, double gravity, int page,
int size) {
return entryRepository.findAllByRanking(date, gravity, PageRequest.of(page, size));
public Page<Entry> fetchByBookmarks(String username, int page, int size) {
Bookmarks bookmarks = bookmarksManager.get(username);
if (bookmarks.getEntries() == null) {
bookmarks.setEntries(Lists.newArrayList());
}
return entryRepository.findAll(qEntry.id.in(bookmarks.getEntries()),
PageRequest.of(page, size, Sort.by(Order.desc("created"))));
}
/**
*
* @param entry
* Apply metadata.
*
* @param username the username
* @param entry the entry
*/
public void applyMetadata(String username, Entry entry) {
if (!entry.getMetadata().containsKey("comments")) {
entry.getMetadata().put("comments", commentManager.count(entry.getId()));
}
if (!entry.getMetadata().containsKey("points")) {
entry.getMetadata().put("points", voteManager.getPoints(entry.getId(), Types.entry));
}
if (!entry.getMetadata().containsKey("bookmarked")) {
entry.getMetadata().put("bookmarked",
bookmarksManager.hasEntry(username, entry.getId()));
}
if (!entry.getMetadata().containsKey("upvoted")) {
entry.getMetadata().put("upvoted",
voteRepository.exists(qVote.target.eq(entry.getId())
.and(qVote.targetType.eq(Types.entry)).and(qVote.type.eq(VoteType.up))
.and(qVote.author.eq(username))));
}
if (!entry.getMetadata().containsKey("downvoted")) {
entry.getMetadata().put("downvoted",
voteRepository.exists(qVote.target.eq(entry.getId())
.and(qVote.targetType.eq(Types.entry))
.and(qVote.type.eq(VoteType.down)).and(qVote.author.eq(username))));
.and(qVote.targetType.eq(Types.entry)).and(qVote.type.eq(VoteType.down))
.and(qVote.author.eq(username))));
}
if (!entry.getMetadata().containsKey("unvote")) {
entry.getMetadata().put("unvote",
voteRepository.exists(
qVote.target.eq(entry.getId()).and(qVote.targetType.eq(Types.entry))
.and(qVote.author.eq(username))));
entry.getMetadata().put("unvote", voteRepository.exists(qVote.target.eq(entry.getId())
.and(qVote.targetType.eq(Types.entry)).and(qVote.author.eq(username))));
}
}
/**
*
* @param entries
* Apply metadata.
*
* @param username the username
* @param entries the entries
*/
public void applyMetadata(String username, List<Entry> entries) {
for (Entry entry : entries) {
@ -123,32 +151,39 @@ public class EntryManager {
}
/**
* @param id
* @return
* Exists.
*
* @param id the id
* @return true, if successful
*/
public boolean exists(Long id) {
return entryRepository.existsById(id);
}
/**
* @param id
* @return
* Gets the.
*
* @param id the id
* @return the entry
*/
public Entry get(Long id) {
return entryRepository.findById(id).orElse(null);
}
/**
* @param entry
* @return
* Save.
*
* @param entry the entry
* @return the entry
*/
public Entry save(Entry entry) {
return entryRepository.save(entry);
}
/**
*
* @param entry
* Delete.
*
* @param entry the entry
*/
public void delete(Entry entry) {
commentManager.deleteByTarget(entry.getId());
@ -157,9 +192,10 @@ public class EntryManager {
}
/**
*
* @param entryId
* @return
* Gets the points.
*
* @param entryId the entry id
* @return the points
*/
public long getPoints(Long entryId) {
long upvotes = voteRepository.count(qVote.targetType.eq(Types.entry)

View File

@ -12,48 +12,51 @@ import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
/**
* @author _bastler@bstly.de
*
* The Class InstantHelper.
*/
public class InstantHelper {
/**
*
* @param instant
* @param amount
* @return
* Plus.
*
* @param instant the instant
* @param amount the amount
* @return the instant
*/
public static Instant plus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
* Plus.
*
* @param instant the instant
* @param amountToAdd the amount to add
* @param unit the unit
* @return the instant
*/
public static Instant plus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amountToAdd, unit).toInstant();
}
/**
*
* @param instant
* @param amount
* @return
* Minus.
*
* @param instant the instant
* @param amount the amount
* @return the instant
*/
public static Instant minus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
* Minus.
*
* @param instant the instant
* @param amountToAdd the amount to add
* @param unit the unit
* @return the instant
*/
public static Instant minus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amountToAdd, unit)
@ -61,10 +64,11 @@ public class InstantHelper {
}
/**
*
* @param instant
* @param unit
* @return
* Truncate.
*
* @param instant the instant
* @param unit the unit
* @return the instant
*/
public static Instant truncate(Instant instant, TemporalUnit unit) {
if (ChronoUnit.YEARS.equals(unit)) {

View File

@ -34,8 +34,7 @@ import de.bstly.board.repository.EntryRepository;
import de.bstly.board.repository.LocalUserRepository;
/**
* @author monitoring@bstly.de
*
* The Class UserManager.
*/
@Service
public class UserManager implements UserDetailsService, SmartInitializingSingleton {
@ -44,18 +43,27 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet
@Autowired
private LocalUserRepository localUserRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private EntryManager entryManager;
@Autowired
private EntryRepository entryRepository;
private QLocalUser qLocalUser = QLocalUser.localUser;
private QEntry qEntry = QEntry.entry;
@Value("${admin.password:}")
private String adminPassword;
/*
* @see org.springframework.security.core.userdetails.UserDetailsService#
* loadUserByUsername(java.lang.String)
*/
/*
* @see
* de.bstly.board.businesslogic.LocalUserManager#loadUserByUsername(java.lang.
@ -79,6 +87,10 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet
return new User(username, localUser.getPasswordHash(), authorities);
}
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()
*/
/*
*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
@ -102,27 +114,30 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet
}
/**
*
* @param username
* @return
* Gets the by username.
*
* @param username the username
* @return the by username
*/
public LocalUser getByUsername(String username) {
return localUserRepository.findById(username).orElse(null);
}
/**
*
* @param externalId
* @return
* Gets the by external id.
*
* @param externalId the external id
* @return the by external id
*/
public LocalUser getByExternalId(String externalId) {
return localUserRepository.findOne(qLocalUser.externalId.eq(externalId)).orElse(null);
}
/**
*
* @param authentication
* @return
* Gets the by auth.
*
* @param authentication the authentication
* @return the by auth
*/
public LocalUser getByAuth(Authentication authentication) {
if (authentication != null) {
@ -181,8 +196,10 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet
}
/**
*
* @param user
* Apply metadata.
*
* @param username the username
* @param user the user
*/
public void applyMetadata(String username, LocalUser user) {
if (user.getUsername().equals(username) && !user.getMetadata().containsKey("self")) {
@ -199,17 +216,20 @@ public class UserManager implements UserDetailsService, SmartInitializingSinglet
}
/**
*
* @param localUser
* @return
* Save.
*
* @param localUser the local user
* @return the local user
*/
public LocalUser save(LocalUser localUser) {
return localUserRepository.save(localUser);
}
/**
* @param username
* @return
* Exists.
*
* @param username the username
* @return true, if successful
*/
public boolean exists(String username) {
return localUserRepository.existsById(username);

View File

@ -13,22 +13,23 @@ import de.bstly.board.model.VoteType;
import de.bstly.board.repository.VoteRepository;
/**
* @author Lurkars
*
* The Class VoteManager.
*/
@Component
public class VoteManager {
@Autowired
private VoteRepository voteRepository;
private QVote qVote = QVote.vote;
/**
*
* @param author
* @param targetType
* @param target
* @return
* Gets the.
*
* @param author the author
* @param targetType the target type
* @param target the target
* @return the vote
*/
public Vote get(String author, Types targetType, Long target) {
return voteRepository.findOne(qVote.author.eq(author).and(qVote.targetType.eq(targetType))
@ -36,25 +37,29 @@ public class VoteManager {
}
/**
*
* @param vote
* @return
* Save.
*
* @param vote the vote
* @return the vote
*/
public Vote save(Vote vote) {
return voteRepository.save(vote);
}
/**
*
* @param vote
* Delete.
*
* @param vote the vote
*/
public void delete(Vote vote) {
voteRepository.delete(vote);
}
/**
*
* @param vote
* Delete by target.
*
* @param target the target
* @param targetType the target type
*/
public void deleteByTarget(Long target, Types targetType) {
for (Vote vote : voteRepository
@ -64,10 +69,11 @@ public class VoteManager {
}
/**
*
* @param target
* @param targetType
* @return
* Gets the points.
*
* @param target the target
* @param targetType the target type
* @return the points
*/
public Long getPoints(Long target, Types targetType) {
return voteRepository

View File

@ -11,49 +11,53 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
/**
* @author _bastler@bstly.de
*
* The Class InstantHelper.
*/
public class InstantHelper {
/**
*
* @param instant
* @param amount
* @return
* Plus.
*
* @param instant the instant
* @param amount the amount
* @return the instant
*/
public static Instant plus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
* Plus.
*
* @param instant the instant
* @param amountToAdd the amount to add
* @param unit the unit
* @return the instant
*/
public static Instant plus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).plus(amountToAdd, unit).toInstant();
}
/**
*
* @param instant
* @param amount
* @return
* Minus.
*
* @param instant the instant
* @param amount the amount
* @return the instant
*/
public static Instant minus(Instant instant, TemporalAmount amount) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amount).toInstant();
}
/**
*
* @param instant
* @param amountToAdd
* @param unit
* @return
* Minus.
*
* @param instant the instant
* @param amountToAdd the amount to add
* @param unit the unit
* @return the instant
*/
public static Instant minus(Instant instant, long amountToAdd, TemporalUnit unit) {
return ZonedDateTime.ofInstant(instant, ZoneOffset.UTC).minus(amountToAdd, unit)
@ -61,10 +65,11 @@ public class InstantHelper {
}
/**
*
* @param instant
* @param unit
* @return
* Truncate.
*
* @param instant the instant
* @param unit the unit
* @return the instant
*/
public static Instant truncate(Instant instant, TemporalUnit unit) {
if (ChronoUnit.YEARS.equals(unit)) {

View File

@ -17,23 +17,25 @@ import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
/**
*
* @author _bastler@bstly.de
*
* The Class AuthenticationController.
*/
@RestController
@RequestMapping("/auth")
public class AuthenticationController extends BaseController {
private static String authorizationRequestBaseUri = "oauth2/authorization";
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
/**
*
* @return
* Me.
*
* @return the authentication
*/
@GetMapping
public Authentication me() {
@ -42,8 +44,9 @@ public class AuthenticationController extends BaseController {
}
/**
*
* @return
* Gets the external login urls.
*
* @return the external login urls
*/
@SuppressWarnings("unchecked")
@GetMapping("external")
@ -66,14 +69,22 @@ public class AuthenticationController extends BaseController {
return clients;
}
/**
* The Class Client.
*/
protected static class Client {
private String id;
private String loginUrl;
/**
* @param id
* @param loginUrl
* Instantiates a new client.
*
* @param id the id
* @param loginUrl the login url
*/
public Client(String id, String loginUrl) {
super();
@ -82,6 +93,8 @@ public class AuthenticationController extends BaseController {
}
/**
* Gets the id.
*
* @return the id
*/
public String getId() {
@ -89,21 +102,27 @@ public class AuthenticationController extends BaseController {
}
/**
* @param id the id to set
* Sets the id.
*
* @param id the new id
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the loginUrl
* Gets the login url.
*
* @return the login url
*/
public String getLoginUrl() {
return loginUrl;
}
/**
* @param loginUrl the loginUrl to set
* Sets the login url.
*
* @param loginUrl the new login url
*/
public void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;

View File

@ -10,18 +10,20 @@ import org.springframework.security.core.context.SecurityContextHolder;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.model.LocalUser;
/**
* @author monitoring@bstly.de
*
* The Class BaseController.
*/
public class BaseController {
@Autowired
private UserManager localUserManager;
/**
*
* @return
* Authenticated.
*
* @return true, if successful
*/
protected boolean authenticated() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
@ -29,8 +31,9 @@ public class BaseController {
}
/**
*
* @return
* Gets the current username.
*
* @return the current username
*/
protected String getCurrentUsername() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
@ -38,8 +41,9 @@ public class BaseController {
}
/**
*
* @return
* Gets the local user.
*
* @return the local user
*/
protected LocalUser getLocalUser() {
return localUserManager.getByAuth(SecurityContextHolder.getContext().getAuthentication());

View File

@ -0,0 +1,100 @@
/**
*
*/
package de.bstly.board.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import de.bstly.board.businesslogic.BookmarksManager;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.controller.support.EntityResponseStatusException;
import de.bstly.board.model.Entry;
/**
* The Class BookmarksController.
*/
@RestController
@RequestMapping("/b")
public class BookmarksController extends BaseController {
@Autowired
private BookmarksManager bookmarksManager;
@Autowired
private EntryManager entryManager;
@Value("${bstly.board.size:30}")
private int SIZE;
/**
* Gets the entries.
*
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @return the entries
*/
@PreAuthorize("isAuthenticated()")
@GetMapping()
public Page<Entry> getEntries(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
if (sizeParameter.isPresent() && sizeParameter.get() > 100) {
sizeParameter = Optional.of(100);
}
Page<Entry> entries = entryManager.fetchByBookmarks(getCurrentUsername(),
pageParameter.orElse(0), sizeParameter.orElse(SIZE));
entryManager.applyMetadata(getCurrentUsername(), entries.getContent());
return entries;
}
/**
* Adds the entry.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@PutMapping("/{id}")
public void addEntry(@PathVariable("id") Long id) {
if (!entryManager.exists(id)) {
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (bookmarksManager.hasEntry(getCurrentUsername(), id)) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
bookmarksManager.addEntry(getCurrentUsername(), id);
}
/**
* Removes the entry.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/{id}")
public void removeEntry(@PathVariable("id") Long id) {
if (!entryManager.exists(id)) {
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (!bookmarksManager.hasEntry(getCurrentUsername(), id)) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
bookmarksManager.removeEntry(getCurrentUsername(), id);
}
}

View File

@ -29,26 +29,45 @@ import de.bstly.board.model.Types;
import de.bstly.board.model.Vote;
import de.bstly.board.model.VoteType;
/**
* @author Lurkars
*
* The Class CommentController.
*/
@RestController
@RequestMapping("/c")
public class CommentController extends BaseController {
@Autowired
private CommentManager commentManager;
@Autowired
private CommentValidator commentValidator;
@Autowired
private VoteManager voteManager;
@Value("${bstly.board.size:30}")
private int SIZE;
@Value("${bstly.board.ranking.gravity:1.8}")
private double GRAVITY;
/**
* Ranked comments.
*
* @param target the target
* @param parent the parent
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param dateParameter the date parameter
* @param gravityParameter the gravity parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping({ "/e/{target}", "/e/{target}/{parent}" })
public Page<Comment> rankedComments(@PathVariable("target") Long target,
@ -69,6 +88,13 @@ public class CommentController extends BaseController {
// return comments;
}
/**
* Count comments.
*
* @param target the target
* @param parent the parent
* @return the long
*/
@PreAuthorize("isAuthenticated()")
@GetMapping({ "/c/{target}", "/c/{target}/{parent}" })
public Long countComments(@PathVariable("target") Long target,
@ -76,6 +102,16 @@ public class CommentController extends BaseController {
return commentManager.count(target, parent.orElse(null));
}
/**
* New comments.
*
* @param target the target
* @param parent the parent
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param dateParameter the date parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping({ "/e/new/{target}", "/e/new/{target}/{parent}" })
public Page<Comment> newComments(@PathVariable("target") Long target,
@ -90,6 +126,12 @@ public class CommentController extends BaseController {
return comments;
}
/**
* Gets the comment.
*
* @param id the id
* @return the comment
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/{id}")
public Comment getComment(@PathVariable("id") Long id) {
@ -104,6 +146,12 @@ public class CommentController extends BaseController {
return comment;
}
/**
* Creates the comment.
*
* @param comment the comment
* @return the comment
*/
@PreAuthorize("isAuthenticated()")
@PostMapping()
public Comment createComment(@RequestBody Comment comment) {

View File

@ -32,61 +32,91 @@ import de.bstly.board.repository.CommentRepository;
import de.bstly.board.repository.LocalUserRepository;
import de.bstly.board.repository.VoteRepository;
/**
*
* @author _bastler@bstly.de
*
* The Class DebugController.
*/
@RestController
@RequestMapping("/debug")
public class DebugController extends BaseController {
/**
* logger
*/
private Logger logger = LogManager.getLogger(DebugController.class);
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private LocalUserRepository localUserRepository;
@Autowired
private CommentRepository commentRepository;
@Autowired
private VoteRepository voteRepository;
@Autowired
private EntryManager entryManager;
@Value("${debug.random.users:0}")
private int users;
@Value("${debug.random.minEntries:0}")
private int minEntries;
@Value("${debug.random.maxEntries:10}")
private int maxEntries;
@Value("${debug.random.entryAge:63115200}")
private long entryAge;
@Value("${debug.random.minComments:0}")
private int minComments;
@Value("${debug.random.maxComments:10}")
private int maxComments;
@Value("${debug.random.subCommentsFactor:0.5}")
private double subCommentsFactor;
@Value("${debug.random.subCommentsThresh:0.3}")
private double subCommentsThresh;
@Value("${debug.random.subCommentsDepth:2}")
private int subCommentsDepth;
@Value("${debug.random.minUpvotes:5}")
private int minUpvotes;
@Value("${debug.random.maxUpvotes:10}")
private int maxUpvotes;
@Value("${debug.random.minDownvotes:0}")
private int minDownvotes;
@Value("${debug.random.maxDownvotes:10}")
private int maxDownvotes;
/**
*
* @return
* Random.
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@GetMapping("/random")
@ -120,6 +150,12 @@ public class DebugController extends BaseController {
logger.warn("finished random generation");
}
/**
* Entries.
*
* @param username the username
* @param userCount the user count
*/
protected void entries(String username, long userCount) {
long numEntries = RandomUtils.nextLong(minEntries, maxEntries);
for (int i = 0; i < numEntries; i++) {
@ -145,6 +181,13 @@ public class DebugController extends BaseController {
+ "'");
}
/**
* Comments.
*
* @param target the target
* @param date the date
* @param userCount the user count
*/
protected void comments(Long target, Instant date, long userCount) {
long numComments = RandomUtils.nextLong(minComments, maxComments);
logger.debug("Create "
@ -171,6 +214,17 @@ public class DebugController extends BaseController {
}
}
/**
* Sub comments.
*
* @param target the target
* @param parent the parent
* @param date the date
* @param factor the factor
* @param thresh the thresh
* @param depth the depth
* @param userCount the user count
*/
protected void subComments(Long target, Long parent, Instant date, double factor, double thresh,
int depth, long userCount) {
if (depth < subCommentsDepth && RandomUtils.nextDouble(0, 1) < thresh) {
@ -201,6 +255,13 @@ public class DebugController extends BaseController {
}
}
/**
* Votes.
*
* @param target the target
* @param targetType the target type
* @param userCount the user count
*/
protected void votes(Long target, Types targetType, long userCount) {
long numUpvotes = RandomUtils.nextLong(minUpvotes, maxUpvotes);
logger.debug("Create "

View File

@ -34,8 +34,7 @@ import de.bstly.board.model.Vote;
import de.bstly.board.model.VoteType;
/**
* @author Lurkars
*
* The Class EntryController.
*/
@RestController
@RequestMapping("/e")
@ -43,16 +42,28 @@ public class EntryController extends BaseController {
@Autowired
private EntryManager entryManager;
@Autowired
private EntryValidator entryValidator;
@Autowired
private VoteManager voteManager;
@Value("${bstly.board.size:30}")
private int SIZE;
@Value("${bstly.board.ranking.gravity:1.8}")
private double GRAVITY;
/**
* Ranked entries.
*
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param dateParameter the date parameter
* @param gravityParameter the gravity parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping()
public Page<Entry> rankedEntries(@RequestParam("page") Optional<Integer> pageParameter,
@ -64,9 +75,9 @@ public class EntryController extends BaseController {
sizeParameter = Optional.of(100);
}
Page<RankedEntry> entries = entryManager.directFetchByRanking(
dateParameter.orElse(Instant.now()), gravityParameter.orElse(GRAVITY),
pageParameter.orElse(0), sizeParameter.orElse(SIZE));
Page<RankedEntry> entries = entryManager.fetchByRanking(dateParameter.orElse(Instant.now()),
gravityParameter.orElse(GRAVITY), pageParameter.orElse(0),
sizeParameter.orElse(SIZE));
Page<Entry> transformed = new PageImpl<Entry>(
entries.getContent().stream().map(rankedEntry -> Entry.fromRankedEntry(rankedEntry))
@ -77,22 +88,14 @@ public class EntryController extends BaseController {
return transformed;
}
@PreAuthorize("isAuthenticated()")
@GetMapping("ranked")
public Page<Entry> rankedEntries(@RequestParam("page") Optional<Integer> pageParameter,
@RequestParam("size") Optional<Integer> sizeParameter) {
if (sizeParameter.isPresent() && sizeParameter.get() > 100) {
sizeParameter = Optional.of(100);
}
Page<Entry> entries = entryManager.fetchByRanking(pageParameter.orElse(0),
sizeParameter.orElse(SIZE));
entryManager.applyMetadata(getCurrentUsername(), entries.getContent());
return entries;
}
/**
* New entries.
*
* @param pageParameter the page parameter
* @param sizeParameter the size parameter
* @param dateParameter the date parameter
* @return the page
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/new")
public Page<Entry> newEntries(@RequestParam("page") Optional<Integer> pageParameter,
@ -109,6 +112,12 @@ public class EntryController extends BaseController {
return entries;
}
/**
* Gets the entry.
*
* @param id the id
* @return the entry
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/{id}")
public Entry getEntry(@PathVariable("id") Long id) {
@ -119,10 +128,16 @@ public class EntryController extends BaseController {
}
entryManager.applyMetadata(getCurrentUsername(), entry);
return entry;
}
/**
* Creates the entry.
*
* @param entry the entry
* @return the entry
*/
@PreAuthorize("isAuthenticated()")
@PostMapping()
public Entry createEntry(@RequestBody Entry entry) {

View File

@ -8,26 +8,43 @@ import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.common.collect.Lists;
import de.bstly.board.businesslogic.CommentManager;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.controller.support.EntityResponseStatusException;
import de.bstly.board.model.LocalUser;
/**
* @author Lurkars
*
* The Class ModerationController.
*/
@RestController
@RequestMapping("/m")
public class ModerationController {
@Autowired
private CommentManager commentManager;
@Autowired
private EntryManager entryManager;
@Autowired
private UserManager userManager;
/**
* Delete comment.
*
* @param id the id
*/
@PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_MOD')")
@DeleteMapping("/c/{id}")
public void deleteComment(@PathVariable("id") Long id) {
@ -38,6 +55,11 @@ public class ModerationController {
commentManager.delete(commentManager.get(id));
}
/**
* Delete entry.
*
* @param id the id
*/
@PreAuthorize("hasRole('ROLE_ADMIN') || hasRole('ROLE_MOD')")
@DeleteMapping("/e/{id}")
public void deleteEntry(@PathVariable("id") Long id) {
@ -47,4 +69,58 @@ public class ModerationController {
entryManager.delete(entryManager.get(id));
}
/**
* Make mod.
*
* @param username the username
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PutMapping("/u/{username}")
public void makeMod(@PathVariable("username") String username) {
LocalUser user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (user.getRoles() == null) {
user.setRoles(Lists.newArrayList());
}
if (user.getRoles().contains("ROLE_MOD")) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
user.getRoles().add("ROLE_MOD");
userManager.save(user);
}
/**
* Unmake mode.
*
* @param username the username
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/u/{username}")
public void unmakeMode(@PathVariable("username") String username) {
LocalUser user = userManager.getByUsername(username);
if (user == null) {
throw new EntityResponseStatusException(HttpStatus.UNPROCESSABLE_ENTITY);
}
if (user.getRoles() == null) {
user.setRoles(Lists.newArrayList());
}
if (!user.getRoles().contains("ROLE_MOD")) {
throw new EntityResponseStatusException(HttpStatus.NO_CONTENT);
}
user.getRoles().remove("ROLE_MOD");
userManager.save(user);
}
}

View File

@ -19,17 +19,24 @@ import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.controller.support.EntityResponseStatusException;
import de.bstly.board.model.LocalUser;
/**
* @author monitoring@bstly.de
*
* The Class UserController.
*/
@RestController
@RequestMapping("/u")
public class UserController extends BaseController {
@Autowired
private UserManager userManager;
/**
* Gets the user.
*
* @param usernameParameter the username parameter
* @return the user
*/
@PreAuthorize("isAuthenticated()")
@GetMapping({ "", "/{username}" })
public LocalUser getUser(@PathVariable("username") Optional<String> usernameParameter) {
@ -54,6 +61,12 @@ public class UserController extends BaseController {
return user;
}
/**
* Update user.
*
* @param user the user
* @return the local user
*/
@PreAuthorize("isAuthenticated()")
@PostMapping()
public LocalUser updateUser(@RequestBody LocalUser user) {

View File

@ -21,21 +21,32 @@ import de.bstly.board.model.Types;
import de.bstly.board.model.Vote;
import de.bstly.board.model.VoteType;
/**
* @author monitoring@bstly.de
*
* The Class VoteController.
*/
@RestController
@RequestMapping("/v")
public class VoteController extends BaseController {
@Autowired
private VoteManager voteManager;
@Autowired
private EntryManager entryManager;
@Autowired
private CommentManager commentManager;
/**
* Gets the entry points.
*
* @param id the id
* @return the entry points
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/e/{id}")
public long getEntryPoints(@PathVariable("id") Long id) {
@ -46,6 +57,11 @@ public class VoteController extends BaseController {
return voteManager.getPoints(id, Types.entry);
}
/**
* Vote entry up.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@PutMapping("/e/{id}/up")
public void voteEntryUp(@PathVariable("id") Long id) {
@ -67,6 +83,11 @@ public class VoteController extends BaseController {
}
}
/**
* Vote entry down.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@PutMapping("/e/{id}/down")
public void voteEntryDown(@PathVariable("id") Long id) {
@ -88,6 +109,11 @@ public class VoteController extends BaseController {
}
}
/**
* Unvote entry.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/e/{id}")
public void unvoteEntry(@PathVariable("id") Long id) {
@ -103,6 +129,12 @@ public class VoteController extends BaseController {
voteManager.delete(vote);
}
/**
* Gets the comment points.
*
* @param id the id
* @return the comment points
*/
@PreAuthorize("isAuthenticated()")
@GetMapping("/c/{id}")
public long getCommentPoints(@PathVariable("id") Long id) {
@ -113,6 +145,11 @@ public class VoteController extends BaseController {
return voteManager.getPoints(id, Types.comment);
}
/**
* Vote comment up.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@PutMapping("/c/{id}/up")
public void voteCommentUp(@PathVariable("id") Long id) {
@ -134,6 +171,11 @@ public class VoteController extends BaseController {
}
}
/**
* Vote comment down.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@PutMapping("/c/{id}/down")
public void voteCommentDown(@PathVariable("id") Long id) {
@ -155,6 +197,11 @@ public class VoteController extends BaseController {
}
}
/**
* Unvote comment.
*
* @param id the id
*/
@PreAuthorize("isAuthenticated()")
@DeleteMapping("/c/{id}")
public void unvoteComment(@PathVariable("id") Long id) {

View File

@ -10,19 +10,19 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/**
*
* @author monitoring@bstly.de
*
* The Class ControllerExceptionHandler.
*/
@ControllerAdvice
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
/**
*
* @param exception
* @param request
* @return
* Handle response entity status exception.
*
* @param exception the exception
* @param request the request
* @return the response entity
*/
@ExceptionHandler(value = { EntityResponseStatusException.class })
protected ResponseEntity<Object> handleResponseEntityStatusException(RuntimeException exception,

View File

@ -10,45 +10,47 @@ import org.springframework.core.NestedRuntimeException;
import org.springframework.http.HttpStatus;
import org.springframework.util.Assert;
/**
*
* @author monitoring@bstly.de
*
* The Class EntityResponseStatusException.
*/
public class EntityResponseStatusException extends NestedRuntimeException {
/**
* default serialVersionUID
*/
private static final long serialVersionUID = 1L;
private final HttpStatus status;
@Nullable
private final Object body;
/**
*
* @param status
* Instantiates a new entity response status exception.
*
* @param status the status
*/
public EntityResponseStatusException(HttpStatus status) {
this(null, status);
}
/**
*
* @param body
* @param status
* Instantiates a new entity response status exception.
*
* @param body the body
* @param status the status
*/
public EntityResponseStatusException(@Nullable Object body, HttpStatus status) {
this(body, status, null);
}
/**
*
* @param body
* @param status
* @param cause
* Instantiates a new entity response status exception.
*
* @param body the body
* @param status the status
* @param cause the cause
*/
public EntityResponseStatusException(@Nullable Object body, HttpStatus status, @Nullable Throwable cause) {
super(null, cause);
@ -58,25 +60,26 @@ public class EntityResponseStatusException extends NestedRuntimeException {
}
/**
*
* @return
* Gets the status.
*
* @return the status
*/
public HttpStatus getStatus() {
return this.status;
}
/**
*
* @return
* Gets the body.
*
* @return the body
*/
@Nullable
public Object getBody() {
return this.body;
}
/**
*
* @return
/*
* @see org.springframework.core.NestedRuntimeException#getMessage()
*/
@Override
public String getMessage() {

View File

@ -6,21 +6,21 @@ package de.bstly.board.controller.support;
import org.springframework.lang.Nullable;
import org.springframework.validation.AbstractBindingResult;
/**
*
* @author _bastler@bstly.de
*
* The Class RequestBodyErrors.
*/
@SuppressWarnings("serial")
public class RequestBodyErrors extends AbstractBindingResult {
@Nullable
private final Object target;
/**
*
* @param target
* @param objectName
* Instantiates a new request body errors.
*
* @param target the target
*/
public RequestBodyErrors(@Nullable Object target) {
super("request-body");
@ -35,6 +35,9 @@ public class RequestBodyErrors extends AbstractBindingResult {
return target;
}
/*
* @see org.springframework.validation.AbstractBindingResult#getActualFieldValue(java.lang.String)
*/
/*
* @see
* org.springframework.validation.AbstractBindingResult#getActualFieldValue(java

View File

@ -13,15 +13,18 @@ import de.bstly.board.businesslogic.CommentManager;
import de.bstly.board.businesslogic.EntryManager;
import de.bstly.board.model.Comment;
/**
* @author monitoring@bstly.de
*
* The Class CommentValidator.
*/
@Component
public class CommentValidator implements Validator {
@Autowired
private CommentManager commentManager;
@Autowired
private EntryManager entryManager;

View File

@ -12,13 +12,14 @@ import org.springframework.validation.Validator;
import de.bstly.board.model.Entry;
import de.bstly.board.model.EntryType;
/**
* @author monitoring@bstly.de
*
* The Class EntryValidator.
*/
@Component
public class EntryValidator implements Validator {
private UrlValidator urlValidator = new UrlValidator();
/*

View File

@ -7,19 +7,19 @@ import org.springframework.context.ApplicationEvent;
import de.bstly.board.model.Vote;
/**
* @author Lurkars
*
* The Class VotedEvent.
*/
public class VotedEvent extends ApplicationEvent {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* @param source
* Instantiates a new voted event.
*
* @param vote the vote
*/
public VotedEvent(Vote vote) {
super(vote);

View File

@ -28,34 +28,42 @@ import com.google.gson.JsonParser;
import de.bstly.board.i18n.model.I18n;
import de.bstly.board.i18n.repository.I18nRepository;
/**
* @author _bastler@bstly.de
*
* The Class I18nManager.
*/
@Component
public class I18nManager implements SmartInitializingSingleton {
private Logger logger = LoggerFactory.getLogger(I18nManager.class);
@Autowired
private I18nRepository i18nRepository;
@Autowired
private ResourceLoader resourceLoader;
private Gson gson = new Gson();
/**
*
* @param locale
* @return
* Gets the.
*
* @param locale the locale
* @return the i 18 n
*/
public I18n get(String locale) {
return i18nRepository.findById(locale).orElse(null);
}
/**
*
* @param locale
* @return
* Gets the label.
*
* @param locale the locale
* @return the label
*/
public JsonObject getLabel(String locale) {
I18n i18n = get(locale);
@ -70,17 +78,19 @@ public class I18nManager implements SmartInitializingSingleton {
}
/**
*
* @return
* Gets the locales.
*
* @return the locales
*/
public List<String> getLocales() {
return i18nRepository.findAll().stream().map(I18n::getLocale).collect(Collectors.toList());
}
/**
*
* @param dest
* @param src
* Extend json object.
*
* @param dest the dest
* @param src the src
*/
protected void extendJsonObject(JsonObject dest, JsonObject src) {
for (Entry<String, JsonElement> srcEntry : src.entrySet()) {
@ -100,10 +110,11 @@ public class I18nManager implements SmartInitializingSingleton {
}
/**
*
* @param locale
* @param newLabel
* @return
* Adds the label.
*
* @param locale the locale
* @param newLabel the new label
* @return the i 18 n
*/
public I18n addLabel(String locale, JsonObject newLabel) {
JsonObject label = getLabel(locale);
@ -122,10 +133,11 @@ public class I18nManager implements SmartInitializingSingleton {
}
/**
*
* @param locale
* @param label
* @return
* Sets the label.
*
* @param locale the locale
* @param label the label
* @return the i 18 n
*/
public I18n setLabel(String locale, JsonObject label) {
I18n i18n = new I18n();
@ -136,8 +148,9 @@ public class I18nManager implements SmartInitializingSingleton {
}
/**
*
* @param locale
* Delete label.
*
* @param locale the locale
*/
public void deleteLabel(String locale) {
if (i18nRepository.existsById(locale)) {
@ -145,6 +158,9 @@ public class I18nManager implements SmartInitializingSingleton {
}
}
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()
*/
/*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()

View File

@ -27,21 +27,25 @@ import com.google.gson.JsonObject;
import de.bstly.board.controller.BaseController;
import de.bstly.board.i18n.businesslogic.I18nManager;
/**
* @author _bastler@bstly.de
*
* The Class I18nController.
*/
@RestController
@RequestMapping("/i18n")
public class I18nController extends BaseController {
@Autowired
private I18nManager i18nManager;
private Gson gson = new Gson();
/**
*
* @return
* Gets the locales.
*
* @return the locales
*/
@GetMapping
public List<String> getLocales() {
@ -49,11 +53,13 @@ public class I18nController extends BaseController {
}
/**
*
* @param locale
* @param response
* @throws JsonIOException
* @throws IOException
* Gets the label.
*
* @param locale the locale
* @param response the response
* @return the label
* @throws JsonIOException the json IO exception
* @throws IOException Signals that an I/O exception has occurred.
*/
@GetMapping("/{locale}")
public void getLabel(@PathVariable("locale") String locale, HttpServletResponse response)
@ -66,9 +72,10 @@ public class I18nController extends BaseController {
}
/**
*
* @param locale
* @param label
* Sets the label.
*
* @param locale the locale
* @param label the label
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/{locale}")
@ -81,9 +88,10 @@ public class I18nController extends BaseController {
}
/**
*
* @param locale
* @param label
* Adds the label.
*
* @param locale the locale
* @param label the label
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PutMapping("/{locale}")
@ -96,8 +104,9 @@ public class I18nController extends BaseController {
}
/**
*
* @param locale
* Delete locale.
*
* @param locale the locale
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@DeleteMapping("/{locale}")

View File

@ -10,30 +10,27 @@ import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
*
* @author _bastler@bstly.de
*
* The Class I18n.
*/
@Entity
@Table(name = "i18n", uniqueConstraints = @UniqueConstraint(columnNames = { "locale" }))
public class I18n {
/**
*
*/
@Id
@Column(name = "locale", unique = true, nullable = false)
private String locale;
/**
*
*/
@Lob
@Column(name = "label")
private String label;
/**
* Gets the locale.
*
* @return the locale
*/
public String getLocale() {
@ -41,13 +38,17 @@ public class I18n {
}
/**
* @param locale the locale to set
* Sets the locale.
*
* @param locale the new locale
*/
public void setLocale(String locale) {
this.locale = locale;
}
/**
* Gets the label.
*
* @return the label
*/
public String getLabel() {
@ -55,7 +56,9 @@ public class I18n {
}
/**
* @param label the label to set
* Sets the label.
*
* @param label the new label
*/
public void setLabel(String label) {
this.label = label;

View File

@ -10,9 +10,7 @@ import org.springframework.stereotype.Repository;
import de.bstly.board.i18n.model.I18n;
/**
*
* @author _bastler@bstly.de
*
* The Interface I18nRepository.
*/
@Repository
public interface I18nRepository

View File

@ -0,0 +1,90 @@
/**
*
*/
package de.bstly.board.model;
import java.util.List;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.google.common.collect.Lists;
/**
* The Class Bookmarks.
*/
@Entity
@Table(name = "bookmarks")
@EntityListeners({ AuditingEntityListener.class })
public class Bookmarks {
@Id
@Column(name = "username", nullable = false)
private String username;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "bookmark_entries")
private List<Long> entries;
/**
* @param username
*/
public Bookmarks() {
super();
}
/**
* @param username
*/
public Bookmarks(String username) {
super();
this.username = username;
this.entries = Lists.newArrayList();
}
/**
* Gets the username.
*
* @return the username
*/
public String getUsername() {
return username;
}
/**
* Sets the username.
*
* @param username the new username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Gets the entries.
*
* @return the entries
*/
public List<Long> getEntries() {
return entries;
}
/**
* Sets the entries.
*
* @param entries the new entries
*/
public void setEntries(List<Long> entries) {
this.entries = entries;
}
}

View File

@ -20,34 +20,49 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.google.common.collect.Maps;
/**
* @author Lurkars
*
* The Class Comment.
*/
@Entity
@Table(name = "comments")
@EntityListeners({ AuditingEntityListener.class })
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "author", nullable = false)
private String author;
@Column(name = "created", nullable = false)
private Instant created;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "parent", nullable = true)
private Long parent;
@Lob
@Column(name = "text", nullable = false)
private String text;
@Transient
private Map<String, Object> metadata;
/**
* Gets the id.
*
* @return the id
*/
public Long getId() {
@ -55,13 +70,17 @@ public class Comment {
}
/**
* @param id the id to set
* Sets the id.
*
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Gets the author.
*
* @return the author
*/
public String getAuthor() {
@ -69,13 +88,17 @@ public class Comment {
}
/**
* @param author the author to set
* Sets the author.
*
* @param author the new author
*/
public void setAuthor(String author) {
this.author = author;
}
/**
* Gets the created.
*
* @return the created
*/
public Instant getCreated() {
@ -83,13 +106,17 @@ public class Comment {
}
/**
* @param created the created to set
* Sets the created.
*
* @param created the new created
*/
public void setCreated(Instant created) {
this.created = created;
}
/**
* Gets the target.
*
* @return the target
*/
public Long getTarget() {
@ -97,13 +124,17 @@ public class Comment {
}
/**
* @param target the target to set
* Sets the target.
*
* @param target the new target
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* Gets the parent.
*
* @return the parent
*/
public Long getParent() {
@ -111,13 +142,17 @@ public class Comment {
}
/**
* @param parent the parent to set
* Sets the parent.
*
* @param parent the new parent
*/
public void setParent(Long parent) {
this.parent = parent;
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
@ -125,13 +160,17 @@ public class Comment {
}
/**
* @param text the text to set
* Sets the text.
*
* @param text the new text
*/
public void setText(String text) {
this.text = text;
}
/**
* Gets the metadata.
*
* @return the metadata
*/
public Map<String, Object> getMetadata() {
@ -143,7 +182,9 @@ public class Comment {
}
/**
* @param metadata the metadata to set
* Sets the metadata.
*
* @param metadata the metadata
*/
public void setMetadata(Map<String, Object> metadata) {
this.metadata = metadata;

View File

@ -22,42 +22,63 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.google.common.collect.Maps;
/**
* @author Lurkars
*
* The Class Entry.
*/
@Entity
@Table(name = "entries")
@EntityListeners({ AuditingEntityListener.class })
public class Entry {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
private Long id;
@Column(name = "author", nullable = false)
private String author;
@Column(name = "created", nullable = false)
private Instant created;
@Enumerated(EnumType.STRING)
@Column(name = "entry_type", nullable = false)
private EntryType entryType;
@Enumerated(EnumType.STRING)
@Column(name = "entry_status", nullable = false, columnDefinition = "varchar(255) default 'NORMAL'")
private EntryStatus entryStatus;
@Column(name = "url")
private String url;
@Column(name = "title", nullable = false)
private String title;
@Lob
@Column(name = "text")
private String text;
@Transient
private Double ranking;
@Transient
private Map<String, Object> metadata;
/**
* Gets the id.
*
* @return the id
*/
public Long getId() {
@ -65,13 +86,17 @@ public class Entry {
}
/**
* @param id the id to set
* Sets the id.
*
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Gets the author.
*
* @return the author
*/
public String getAuthor() {
@ -79,13 +104,17 @@ public class Entry {
}
/**
* @param author the author to set
* Sets the author.
*
* @param author the new author
*/
public void setAuthor(String author) {
this.author = author;
}
/**
* Gets the created.
*
* @return the created
*/
public Instant getCreated() {
@ -93,41 +122,53 @@ public class Entry {
}
/**
* @param created the created to set
* Sets the created.
*
* @param created the new created
*/
public void setCreated(Instant created) {
this.created = created;
}
/**
* @return the entryType
* Gets the entry type.
*
* @return the entry type
*/
public EntryType getEntryType() {
return entryType;
}
/**
* @param entryType the entryType to set
* Sets the entry type.
*
* @param entryType the new entry type
*/
public void setEntryType(EntryType entryType) {
this.entryType = entryType;
}
/**
* @return the entryStatus
* Gets the entry status.
*
* @return the entry status
*/
public EntryStatus getEntryStatus() {
return entryStatus;
}
/**
* @param entryStatus the entryStatus to set
* Sets the entry status.
*
* @param entryStatus the new entry status
*/
public void setEntryStatus(EntryStatus entryStatus) {
this.entryStatus = entryStatus;
}
/**
* Gets the url.
*
* @return the url
*/
public String getUrl() {
@ -135,13 +176,17 @@ public class Entry {
}
/**
* @param url the url to set
* Sets the url.
*
* @param url the new url
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Gets the title.
*
* @return the title
*/
public String getTitle() {
@ -149,13 +194,17 @@ public class Entry {
}
/**
* @param title the title to set
* Sets the title.
*
* @param title the new title
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Gets the text.
*
* @return the text
*/
public String getText() {
@ -163,13 +212,17 @@ public class Entry {
}
/**
* @param text the text to set
* Sets the text.
*
* @param text the new text
*/
public void setText(String text) {
this.text = text;
}
/**
* Gets the ranking.
*
* @return the ranking
*/
public Double getRanking() {
@ -177,13 +230,17 @@ public class Entry {
}
/**
* @param ranking the ranking to set
* Sets the ranking.
*
* @param ranking the new ranking
*/
public void setRanking(Double ranking) {
this.ranking = ranking;
}
/**
* Gets the metadata.
*
* @return the metadata
*/
public Map<String, Object> getMetadata() {
@ -194,16 +251,19 @@ public class Entry {
}
/**
* @param metadata the metadata to set
* Sets the metadata.
*
* @param metadata the metadata
*/
public void setMetadata(Map<String, Object> metadata) {
this.metadata = metadata;
}
/**
*
* @param rankedEntry
* @return
* From ranked entry.
*
* @param rankedEntry the ranked entry
* @return the entry
*/
public static Entry fromRankedEntry(RankedEntry rankedEntry) {
Entry entry = new Entry();

View File

@ -3,12 +3,17 @@
*/
package de.bstly.board.model;
/**
* @author Lurkars
*
* The Enum EntryStatus.
*/
public enum EntryStatus {
NORMAL, ARCHIVED, PINNED
NORMAL,
ARCHIVED,
PINNED
}

View File

@ -3,12 +3,19 @@
*/
package de.bstly.board.model;
/**
* @author Lurkars
*
* The Enum EntryType.
*/
public enum EntryType {
DISCUSSION, INTERN, LINK, QUESTION
DISCUSSION,
INTERN,
LINK,
QUESTION
}

View File

@ -23,44 +23,65 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.google.common.collect.Maps;
/**
* @author monitoring@bstly.de
*
* The Class LocalUser.
*/
@Entity
@Table(name = "users")
@JsonInclude(Include.NON_EMPTY)
public class LocalUser {
@Id
@Column(name = "username", nullable = false)
private String username;
@Column(name = "external_id", nullable = true)
private String externalId;
@JsonIgnore
@Column(name = "password_hash", nullable = true)
private String passwordHash;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "users_roles")
private List<String> roles;
@Lob
@Column(name = "about", nullable = true)
private String about;
@Column(name = "email", nullable = true)
private String email;
@Column(name = "locale", nullable = false, columnDefinition = "varchar(255) default 'en'")
private String locale;
@Column(name = "dark_theme", columnDefinition = "boolean default false")
private boolean darkTheme;
@ElementCollection
@LazyCollection(LazyCollectionOption.FALSE)
@CollectionTable(name = "users_settings")
private Map<String, String> settings;
@Transient
private Map<String, Object> metadata;
/**
* Gets the username.
*
* @return the username
*/
public String getUsername() {
@ -68,41 +89,53 @@ public class LocalUser {
}
/**
* @param username the username to set
* Sets the username.
*
* @param username the new username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the externalId
* Gets the external id.
*
* @return the external id
*/
public String getExternalId() {
return externalId;
}
/**
* @param externalId the externalId to set
* Sets the external id.
*
* @param externalId the new external id
*/
public void setExternalId(String externalId) {
this.externalId = externalId;
}
/**
* @return the passwordHash
* Gets the password hash.
*
* @return the password hash
*/
public String getPasswordHash() {
return passwordHash;
}
/**
* @param passwordHash the passwordHash to set
* Sets the password hash.
*
* @param passwordHash the new password hash
*/
public void setPasswordHash(String passwordHash) {
this.passwordHash = passwordHash;
}
/**
* Gets the roles.
*
* @return the roles
*/
public List<String> getRoles() {
@ -110,13 +143,17 @@ public class LocalUser {
}
/**
* @param roles the roles to set
* Sets the roles.
*
* @param roles the new roles
*/
public void setRoles(List<String> roles) {
this.roles = roles;
}
/**
* Gets the about.
*
* @return the about
*/
public String getAbout() {
@ -124,13 +161,17 @@ public class LocalUser {
}
/**
* @param about the about to set
* Sets the about.
*
* @param about the new about
*/
public void setAbout(String about) {
this.about = about;
}
/**
* Gets the email.
*
* @return the email
*/
public String getEmail() {
@ -138,13 +179,17 @@ public class LocalUser {
}
/**
* @param email the email to set
* Sets the email.
*
* @param email the new email
*/
public void setEmail(String email) {
this.email = email;
}
/**
* Gets the locale.
*
* @return the locale
*/
public String getLocale() {
@ -152,27 +197,35 @@ public class LocalUser {
}
/**
* @param locale the locale to set
* Sets the locale.
*
* @param locale the new locale
*/
public void setLocale(String locale) {
this.locale = locale;
}
/**
* @return the darkTheme
* Checks if is dark theme.
*
* @return true, if is dark theme
*/
public boolean isDarkTheme() {
return darkTheme;
}
/**
* @param darkTheme the darkTheme to set
* Sets the dark theme.
*
* @param darkTheme the new dark theme
*/
public void setDarkTheme(boolean darkTheme) {
this.darkTheme = darkTheme;
}
/**
* Gets the settings.
*
* @return the settings
*/
public Map<String, String> getSettings() {
@ -180,13 +233,17 @@ public class LocalUser {
}
/**
* @param settings the settings to set
* Sets the settings.
*
* @param settings the settings
*/
public void setSettings(Map<String, String> settings) {
this.settings = settings;
}
/**
* Gets the metadata.
*
* @return the metadata
*/
public Map<String, Object> getMetadata() {
@ -197,7 +254,9 @@ public class LocalUser {
}
/**
* @param metadata the metadata to set
* Sets the metadata.
*
* @param metadata the metadata
*/
public void setMetadata(Map<String, Object> metadata) {
this.metadata = metadata;

View File

@ -10,25 +10,34 @@ import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @author monitoring@bstly.de
*
* The Class PersistentLogin.
*/
@Entity
@Table(name = "persistent_logins")
public class PersistentLogin {
@Column(name = "username", length = 64, nullable = false)
private String username;
@Id
@Column(name = "series", length = 64)
private String series;
@Column(name = "token", length = 64, nullable = false)
private String token;
@Column(name = "last_used", nullable = false)
private Instant last_used;
/**
* Gets the username.
*
* @return the username
*/
public String getUsername() {
@ -36,13 +45,17 @@ public class PersistentLogin {
}
/**
* @param username the username to set
* Sets the username.
*
* @param username the new username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Gets the series.
*
* @return the series
*/
public String getSeries() {
@ -50,13 +63,17 @@ public class PersistentLogin {
}
/**
* @param series the series to set
* Sets the series.
*
* @param series the new series
*/
public void setSeries(String series) {
this.series = series;
}
/**
* Gets the token.
*
* @return the token
*/
public String getToken() {
@ -64,21 +81,27 @@ public class PersistentLogin {
}
/**
* @param token the token to set
* Sets the token.
*
* @param token the new token
*/
public void setToken(String token) {
this.token = token;
}
/**
* @return the last_used
* Gets the last used.
*
* @return the last used
*/
public Instant getLast_used() {
return last_used;
}
/**
* @param last_used the last_used to set
* Sets the last used.
*
* @param last_used the new last used
*/
public void setLast_used(Instant last_used) {
this.last_used = last_used;

View File

@ -5,27 +5,72 @@ package de.bstly.board.model;
import java.time.Instant;
/**
* @author Lurkars
*
* 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,11 +3,16 @@
*/
package de.bstly.board.model;
/**
* @author Lurkars
*
* The Enum Types.
*/
public enum Types {
comment, entry, user
comment,
entry,
user
}

View File

@ -13,29 +13,40 @@ import javax.persistence.Table;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author Lurkars
*
* The Class Vote.
*/
@Entity
@Table(name = "votes")
@EntityListeners({ AuditingEntityListener.class })
public class Vote {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "target", nullable = false)
private Long target;
@Column(name = "target_type", nullable = false)
private Types targetType;
@Column(name = "author", nullable = false)
private String author;
@Column(name = "type", nullable = false)
private VoteType type;
/**
* Gets the id.
*
* @return the id
*/
public Long getId() {
@ -43,13 +54,17 @@ public class Vote {
}
/**
* @param id the id to set
* Sets the id.
*
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Gets the target.
*
* @return the target
*/
public Long getTarget() {
@ -57,27 +72,35 @@ public class Vote {
}
/**
* @param target the target to set
* Sets the target.
*
* @param target the new target
*/
public void setTarget(Long target) {
this.target = target;
}
/**
* @return the targetType
* Gets the target type.
*
* @return the target type
*/
public Types getTargetType() {
return targetType;
}
/**
* @param targetType the targetType to set
* Sets the target type.
*
* @param targetType the new target type
*/
public void setTargetType(Types targetType) {
this.targetType = targetType;
}
/**
* Gets the author.
*
* @return the author
*/
public String getAuthor() {
@ -85,13 +108,17 @@ public class Vote {
}
/**
* @param author the author to set
* Sets the author.
*
* @param author the new author
*/
public void setAuthor(String author) {
this.author = author;
}
/**
* Gets the type.
*
* @return the type
*/
public VoteType getType() {
@ -99,7 +126,9 @@ public class Vote {
}
/**
* @param type the type to set
* Sets the type.
*
* @param type the new type
*/
public void setType(VoteType type) {
this.type = type;

View File

@ -3,10 +3,15 @@
*/
package de.bstly.board.model;
/**
* @author Lurkars
*
* The Enum VoteType.
*/
public enum VoteType {
up, down
up,
down
}

View File

@ -0,0 +1,19 @@
/**
*
*/
package de.bstly.board.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import de.bstly.board.model.Bookmarks;
/**
* The Interface BookmarksRepository.
*/
@Repository
public interface BookmarksRepository
extends JpaRepository<Bookmarks, String>, QuerydslPredicateExecutor<Bookmarks> {
}

View File

@ -16,28 +16,63 @@ import org.springframework.stereotype.Repository;
import de.bstly.board.model.Comment;
/**
*
* @author monitoring@bstly.de
*
* The Interface CommentRepository.
*/
@Repository
public interface CommentRepository
extends JpaRepository<Comment, Long>, QuerydslPredicateExecutor<Comment> {
/**
* Find all by ranking and parent.
*
* @param target the target
* @param date the date
* @param gravity the gravity
* @return the list
*/
@Query(value = "SELECT comment.*, ranked.ranking FROM comments AS comment LEFT JOIN (SELECT comment.id, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, comment.created, :date)+2,:gravity) AS ranking FROM comments AS comment LEFT JOIN (SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 0 GROUP BY upvote.target) AS upvote ON upvote.target = comment.id LEFT JOIN (SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 GROUP BY downvote.target) AS downvote ON downvote.target = comment.id) as ranked on ranked.id = comment.id WHERE comment.target = :target AND parent IS NULL AND comment.created < :date ORDER BY ranked.ranking DESC, comment.created DESC", countQuery = "SELECT count(*) FROM comments as comment WHERE comment.target = :target AND parent IS NULL AND comment.created < :date", nativeQuery = true)
List<Comment> findAllByRankingAndParent(@Param("target") Long target,
@Param("date") Instant date, @Param("gravity") double gravity);
/**
* Find all by ranking and parent.
*
* @param target the target
* @param parent the parent
* @param date the date
* @param gravity the gravity
* @return the list
*/
@Query(value = "SELECT comment.*, ranked.ranking FROM comments AS comment LEFT JOIN (SELECT comment.id, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, comment.created, :date)+2,:gravity) AS ranking FROM comments AS comment LEFT JOIN (SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 0 GROUP BY upvote.target) AS upvote ON upvote.target = comment.id LEFT JOIN (SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 GROUP BY downvote.target) AS downvote ON downvote.target = comment.id) as ranked on ranked.id = comment.id WHERE comment.target = :target AND parent = :parent AND comment.created < :date ORDER BY ranked.ranking DESC, comment.created DESC", countQuery = "SELECT count(*) FROM comments as comment WHERE comment.target = :target AND parent = :parent AND comment.created < :date", nativeQuery = true)
List<Comment> findAllByRankingAndParent(@Param("target") Long target,
@Param("parent") Long parent, @Param("date") Instant date,
@Param("gravity") double gravity);
/**
* Find all by ranking and parent.
*
* @param target the target
* @param date the date
* @param gravity the gravity
* @param pageable the pageable
* @return the page
*/
@Query(value = "SELECT comment.*, ranked.ranking FROM comments AS comment LEFT JOIN (SELECT comment.id, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, comment.created, :date)+2,:gravity) AS ranking FROM comments AS comment LEFT JOIN (SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 0 GROUP BY upvote.target) AS upvote ON upvote.target = comment.id LEFT JOIN (SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 GROUP BY downvote.target) AS downvote ON downvote.target = comment.id) as ranked on ranked.id = comment.id WHERE comment.target = :target AND parent IS NULL AND comment.created < :date ORDER BY ranked.ranking DESC, comment.created DESC", countQuery = "SELECT count(*) FROM comments as comment WHERE comment.target = :target AND parent IS NULL AND comment.created < :date", nativeQuery = true)
Page<Comment> findAllByRankingAndParent(@Param("target") Long target,
@Param("date") Instant date, @Param("gravity") double gravity, Pageable pageable);
/**
* Find all by ranking and parent.
*
* @param target the target
* @param parent the parent
* @param date the date
* @param gravity the gravity
* @param pageable the pageable
* @return the page
*/
@Query(value = "SELECT comment.*, ranked.ranking FROM comments AS comment LEFT JOIN (SELECT comment.id, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, comment.created, :date)+2,:gravity) AS ranking FROM comments AS comment LEFT JOIN (SELECT upvote.target,COUNT(upvote.id) AS count FROM votes as upvote WHERE upvote.type = 0 AND upvote.target_type = 0 GROUP BY upvote.target) AS upvote ON upvote.target = comment.id LEFT JOIN (SELECT downvote.target,COUNT(downvote.id) AS count FROM votes as downvote WHERE downvote.type = 1 GROUP BY downvote.target) AS downvote ON downvote.target = comment.id) as ranked on ranked.id = comment.id WHERE comment.target = :target AND parent = :parent AND comment.created < :date ORDER BY ranked.ranking DESC, comment.created DESC", countQuery = "SELECT count(*) FROM comments as comment WHERE comment.target = :target AND parent = :parent AND comment.created < :date", nativeQuery = true)
Page<Comment> findAllByRankingAndParent(@Param("target") Long target,
@Param("parent") Long parent, @Param("date") Instant date,

View File

@ -16,41 +16,62 @@ import org.springframework.stereotype.Repository;
import de.bstly.board.model.Entry;
import de.bstly.board.model.RankedEntry;
/**
*
* @author monitoring@bstly.de
*
* The Interface EntryRepository.
*/
@Repository
public interface EntryRepository
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 CALCULATION_QUERY = "SELECT entry.*, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) as points, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, entry.created, :before)+2,:gravity) 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.entry_status = 'NORMAL' ORDER BY ranking DESC, entry.created DESC";
static final String ARCHIVE_CALCULATION_QUERY = "SELECT entry.*, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) as points, (IFNULL(upvote.count,0) - IFNULL(downvote.count,0)) / POW(TIMESTAMPDIFF(HOUR, entry.created, :before)+2,:gravity) 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 ORDER BY ranking DESC, entry.created DESC";
static final String ADDITIONAL_QUERY = "SELECT entry.*, calculation.ranking, calculation.points FROM entries AS entry LEFT JOIN ("
+ CALCULATION_QUERY
+ ") as calculation on calculation.id = entry.id WHERE entry.created < :before ORDER BY calculation.ranking DESC, entry.created DESC";
static final String COUNT_QUERY = "SELECT count(*) FROM entries as entry WHERE entry.created < :before";
/**
* Find all by ranking.
*
* @param before the before
* @param gravity the gravity
* @param pageable the pageable
* @return the page
*/
@Query(value = CALCULATION_QUERY, countQuery = COUNT_QUERY, nativeQuery = true)
Page<RankedEntry> findAllByRanking(@Param("before") Instant before,
@Param("gravity") double gravity, Pageable pageable);
/**
* Find all by ranking archive.
*
* @param before the before
* @param gravity the gravity
* @param pageable the pageable
* @return the page
*/
@Query(value = ARCHIVE_CALCULATION_QUERY, countQuery = COUNT_QUERY, nativeQuery = true)
Page<RankedEntry> findAllByRankingArchive(@Param("before") Instant before,
@Param("gravity") double gravity, Pageable pageable);

View File

@ -10,9 +10,7 @@ import org.springframework.stereotype.Repository;
import de.bstly.board.model.LocalUser;
/**
*
* @author monitoring@bstly.de
*
* The Interface LocalUserRepository.
*/
@Repository
public interface LocalUserRepository

View File

@ -10,9 +10,7 @@ import org.springframework.stereotype.Repository;
import de.bstly.board.model.Vote;
/**
*
* @author monitoring@bstly.de
*
* The Interface VoteRepository.
*/
@Repository
public interface VoteRepository extends JpaRepository<Vote, Long>, QuerydslPredicateExecutor<Vote> {

View File

@ -9,23 +9,27 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
/**
*
* @author _bastler@bstly.de
*
* The Class LocalRememberMeServices.
*/
public class LocalRememberMeServices extends PersistentTokenBasedRememberMeServices {
/**
* @param key
* @param userDetailsService
* @param tokenRepository
* Instantiates a new local remember me services.
*
* @param key the key
* @param userDetailsService the user details service
* @param tokenRepository the token repository
*/
public LocalRememberMeServices(String key, UserDetailsService userDetailsService,
PersistentTokenRepository tokenRepository) {
super(key, userDetailsService, tokenRepository);
}
/*
* @see org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices#rememberMeRequested(javax.servlet.http.HttpServletRequest, java.lang.String)
*/
/*
*
* @see org.springframework.security.web.authentication.rememberme.

View File

@ -4,6 +4,7 @@
package de.bstly.board.security;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -12,36 +13,55 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import com.google.common.collect.Lists;
import de.bstly.board.businesslogic.UserManager;
import de.bstly.board.model.LocalUser;
/**
* @author Lurkars
*
* The Class OAuth2AuthenticationSuccessHandler.
*/
@Component
public class OAuth2AuthenticationSuccessHandler
extends SavedRequestAwareAuthenticationSuccessHandler {
@Autowired
private UserManager localUserManager;
private RememberMeServices rememberMeServices;
/*
* @see org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler#onAuthenticationSuccess(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
LocalUser localUser = localUserManager.getByAuth(authentication);
User user = new User(localUser.getUsername(), "", authentication.getAuthorities());
List<GrantedAuthority> authorities = Lists.newArrayList();
authorities.addAll(authentication.getAuthorities());
if (localUser.getRoles() != null) {
for (String role : localUser.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role));
}
}
User user = new User(localUser.getUsername(), "", authorities);
UsernamePasswordAuthenticationToken newAuthentication = new UsernamePasswordAuthenticationToken(
user, null, authentication.getAuthorities());
user, null, authorities);
SecurityContextHolder.getContext().setAuthentication(newAuthentication);
@ -54,6 +74,11 @@ public class OAuth2AuthenticationSuccessHandler
clearAuthenticationAttributes(request);
}
/**
* Sets the remember me services.
*
* @param rememberMeServices the new remember me services
*/
public void setRememberMeServices(RememberMeServices rememberMeServices) {
this.rememberMeServices = rememberMeServices;
}

View File

@ -25,26 +25,37 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import de.bstly.board.businesslogic.UserManager;
/**
*
* @author monitoring@bstly.de
*
* The Class SecurityConfig.
*/
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserManager localUserManager;
@Autowired
private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
@Autowired
private DataSource dataSource;
@Value("${loginUrl:/login}")
private String loginUrl;
@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.
@ -87,14 +98,20 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
/**
*
* @return
* Password encoder.
*
* @return the argon 2 password encoder
*/
@Bean(name = "passwordEncoder")
public Argon2PasswordEncoder passwordEncoder() {
return new Argon2PasswordEncoder();
}
/**
* Persistent token repository.
*
* @return the persistent token repository
*/
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
@ -102,6 +119,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
return tokenRepository;
}
/**
* Remember me services.
*
* @return the remember me services
*/
@Bean
public RememberMeServices rememberMeServices() {
PersistentTokenBasedRememberMeServices rememberMeServices = new LocalRememberMeServices(