Added forum system

This commit is contained in:
redtea committed 2022-08-30 13:01:42 +03:00
1 parent 0d6fce8c48
commit e49c871fd3
13 files changed
+304 -77

No files matched your search

@@ -60,4 +60,19 @@ public class User {
public int hashCode() {
return getClass().hashCode();
}
public boolean isModer() {
if (roles.contains(Role.MODER) || roles.contains(Role.ADMIN)) return true;
return false;
}
public boolean isAdmin() {
if (roles.contains(Role.ADMIN)) return true;
return false;
}
public boolean isPremium() {
if (roles.contains(Role.PREMIUM) || roles.contains(Role.ADMIN)) return true;
return false;
}
}
@@ -3,17 +3,19 @@ package site.easystartup.web.forum.controller;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.*;
import site.easystartup.web.domain.User;
import site.easystartup.web.forum.domain.Discussion;
import site.easystartup.web.forum.domain.DiscussionMessage;
import site.easystartup.web.forum.domain.DiscussionStatus;
import site.easystartup.web.forum.domain.Topic;
import site.easystartup.web.forum.filter.ForumFilterService;
import site.easystartup.web.forum.service.ForumService;
import site.easystartup.web.forum.repo.TopicRepo;
import site.easystartup.web.service.UserService;
import java.util.Date;
@@ -22,7 +24,9 @@ import java.util.Date;
public class ForumController {
private final TopicRepo topicRepo;
private final ForumFilterService forumFilterService;
private final ForumService forumService;
private final UserService userService;
@GetMapping("/forum")
public String forumMain(Model model) {
@@ -33,8 +37,8 @@ public class ForumController {
@GetMapping("/forum/my")
public String forumMy(Model model) {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
val discussions = forumFilterService.getDiscussionsByAuthor(user.getUsername());
User user = userService.getCurrentUser();
val discussions = forumService.getDiscussionsByAuthor(user.getUsername());
model.addAttribute("discussions", discussions);
return "/my-discussions";
}
@@ -44,37 +48,120 @@ public class ForumController {
return "topic-new";
}
@Secured({"ADMIN", "MODER"})
@PostMapping("/forum/new")
public String forumNewTopic(@RequestParam String title,
@RequestParam String description) {
description = description == null ? "" : description;
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Topic topic = new Topic();
topic.setTitle(title);
topic.setDescription(description);
topic.setAuthor(user.getUsername());
topic.setLast_update(new Date());
topic.setSize(0);
topicRepo.save(topic);
forumService.createTopic(title, description, userService.getCurrentUser());
return "/forum";
}
@GetMapping("/forum/{topic_id}")
public String topicFirstPage(@PathVariable(value = "topic_id") long topic_id,
Model model) {
val pinned_discussions = forumFilterService.getPinnedDiscussionsByTopicId(topic_id);
val pinned_discussions = forumService.getPinnedDiscussionsByTopicId(topic_id);
model.addAttribute("pinned_discussions", pinned_discussions);
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList(0, 14);
val discussions = forumService.getSortedDiscussionsByTopicId(topic_id).subList(0, 14);
model.addAttribute("discussions", discussions);
return "topic-first";
return "/topic-first";
}
@GetMapping("/forum/{topic_id}/page/{page_index}")
public String topicPage(@PathVariable(value = "topic_id") long topic_id,
@PathVariable(value = "topic_id") long page_index,
Model model) {
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList((int)(15 * page_index), (int)(15 * page_index) + 15);
@PathVariable(value = "page_index") long page_index,
Model model) {
val discussions = forumService.getSortedDiscussionsByTopicId(topic_id).subList((int)(15 * page_index), (int)(15 * page_index) + 15);
model.addAttribute("discussions", discussions);
return "topic-content";
return "/topic-content";
}
@GetMapping("/forum/discussion/{discussion_id}")
public String discussion(@PathVariable(value = "discussion_id") long discussion_id,
Model model) {
model.addAttribute("discussion", forumService.getDiscussionById(discussion_id));
model.addAttribute("messages ", forumService.getMessagesByDiscussionId(discussion_id));
return "/discussion";
}
@GetMapping("/forum/{topic_id}/create")
public String discussionCreate(@PathVariable long topic_id) {
return "/discussion-create";
}
@PostMapping("/forum/{topic_id}/create")
public String discussionCreatePost(@PathVariable long topic_id,
@RequestParam String title) {
forumService.createDiscussion(title, topic_id, userService.getCurrentUser());
return "/discussion-create";
}
@GetMapping("/forum/discussion/{discussion_id}/edit")
public String discussionEdit(@PathVariable long discussion_id, Model model) {
Discussion discussion = forumService.getDiscussionById(discussion_id);
User user = userService.getCurrentUser();
if(!(discussion.getAuthor().equals(user.getUsername()) || user.isModer())) return "/403-error";
model.addAttribute("discussion", discussion);
return "/discussion-edit";
}
@PostMapping("/forum/discussion/{discussion_id}/edit")
public String discussionEditPost(@PathVariable long discussion_id,
@RequestParam String title,
@RequestParam DiscussionStatus status,
Model model) {
forumService.editDiscussion(title, discussion_id, status, userService.getCurrentUser());
model.addAttribute("discussion", forumService.getDiscussionById(discussion_id));
model.addAttribute("messages ", forumService.getMessagesByDiscussionId(discussion_id));
return "/discussion";
}
@GetMapping("/forum/discussion/{discussion_id}/add")
public String messageAdd(@PathVariable long discussion_id) {
return "/discussion-message-add";
}
@PostMapping("/forum/discussion/{discussion_id}/add")
public String messageAddPost(@PathVariable long discussion_id,
@RequestParam String text,
Model model) {
forumService.addDiscussionMessage(text, discussion_id, userService.getCurrentUser());
model.addAttribute("discussion", forumService.getDiscussionById(discussion_id));
model.addAttribute("messages ", forumService.getMessagesByDiscussionId(discussion_id));
return "/discussion";
}
@GetMapping("/forum/discussion/{discussion_id}/{message_id}/edit")
public String messageEdit(@PathVariable long discussion_id,
@PathVariable long message_id) {
DiscussionMessage message = forumService.getDiscussionMessageById(message_id);
User user = userService.getCurrentUser();
if(!(message.getSender().equals(user.getUsername()) || user.isModer())) return "/403-error";
return "/discussion-message-edit";
}
@PostMapping("/forum/discussion/{discussion_id}/{message_id}/edit")
public String messageEditPost(@PathVariable long discussion_id,
@RequestParam String text,
Model model, @PathVariable String message_id) {
forumService.editDiscussionMessage(text, discussion_id, userService.getCurrentUser());
model.addAttribute("discussion", forumService.getDiscussionById(discussion_id));
model.addAttribute("messages ", forumService.getMessagesByDiscussionId(discussion_id));
return "/discussion";
}
@DeleteMapping("/forum/discussion/{discussion_id}/{message_id}/delete")
public String messageDelete(@PathVariable long discussion_id,
@PathVariable long message_id,
Model model) {
DiscussionMessage message = forumService.getDiscussionMessageById(message_id);
User user = userService.getCurrentUser();
if(!(message.getSender().equals(user.getUsername()) || user.isModer())) return "/403-error";
model.addAttribute("discussion", forumService.getDiscussionById(discussion_id));
model.addAttribute("messages ", forumService.getMessagesByDiscussionId(discussion_id));
return "/discussion";
}
}
@@ -21,6 +21,7 @@ public class DiscussionMessage {
private String sender;
private Date date;
private boolean edited;
private long discussion_id;
@Override
public boolean equals(Object o) {
@@ -1,51 +0,0 @@
package site.easystartup.web.forum.filter;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import site.easystartup.web.forum.domain.Discussion;
import site.easystartup.web.forum.domain.DiscussionMessage;
import site.easystartup.web.forum.repo.DiscussionMessageRepo;
import site.easystartup.web.forum.repo.DiscussionRepo;
import java.util.Collections;
import java.util.List;
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ForumFilterService {
private final DiscussionMessageRepo discussionMessageRepo;
private final DiscussionRepo discussionRepo;
public List<DiscussionMessage> getMessagesByDiscussionId(long discussionId) {
return Lists.newArrayList(discussionMessageRepo.findAll()).stream()
.filter(m -> m.getId() == discussionId).toList();
}
public List<Discussion> getDiscussionsByAuthor(String author) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> d.getAuthor().equals(author)).toList();
}
public List<Discussion> getDiscussionsByMember(String member) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> getMessagesByDiscussionId(d.getId()).stream()
.anyMatch(m -> m.getSender().equals(member))).toList();
}
public List<Discussion> getPinnedDiscussionsByTopicId(long topic_id) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(Discussion::isPinned)
.filter(d -> d.getTopic() == topic_id).toList();
}
public List<Discussion> getSortedDiscussionsByTopicId(long topic_id) {
List<Discussion> result = Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> !d.isPinned())
.filter(d -> d.getTopic() == topic_id).toList();
Collections.sort(result, Discussion::compareTo);
return result;
}
}
@@ -0,0 +1,131 @@
package site.easystartup.web.forum.service;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import site.easystartup.web.domain.Role;
import site.easystartup.web.domain.User;
import site.easystartup.web.forum.domain.Discussion;
import site.easystartup.web.forum.domain.DiscussionMessage;
import site.easystartup.web.forum.domain.DiscussionStatus;
import site.easystartup.web.forum.domain.Topic;
import site.easystartup.web.forum.repo.DiscussionMessageRepo;
import site.easystartup.web.forum.repo.DiscussionRepo;
import site.easystartup.web.forum.repo.TopicRepo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ForumService {
private final TopicRepo topicRepo;
private final DiscussionMessageRepo discussionMessageRepo;
private final DiscussionRepo discussionRepo;
public List<DiscussionMessage> getMessagesByDiscussionId(long discussionId) {
return Lists.newArrayList(discussionMessageRepo.findAll()).stream()
.filter(m -> m.getDiscussion_id() == discussionId).toList();
}
public Discussion getDiscussionById(long discussionId) {
return discussionRepo.findById(discussionId).get();
}
public List<Discussion> getDiscussionsByAuthor(String author) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> d.getAuthor().equals(author)).toList();
}
public List<Discussion> getDiscussionsByMember(String member) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> getMessagesByDiscussionId(d.getId()).stream()
.anyMatch(m -> m.getSender().equals(member))).toList();
}
public List<Discussion> getPinnedDiscussionsByTopicId(long topic_id) {
return Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(Discussion::isPinned)
.filter(d -> d.getTopic() == topic_id).toList();
}
public List<Discussion> getSortedDiscussionsByTopicId(long topic_id) {
List<Discussion> result = Lists.newArrayList(discussionRepo.findAll()).stream()
.filter(d -> !d.isPinned())
.filter(d -> d.getTopic() == topic_id).toList();
Collections.sort(result, Discussion::compareTo);
return result;
}
public void createTopic(String title, String description, User user) {
description = description == null ? "" : description;
Topic topic = new Topic();
topic.setTitle(title);
topic.setDescription(description);
topic.setAuthor(user.getUsername());
topic.setLast_update(new Date());
topic.setSize(0);
topicRepo.save(topic);
}
public void createDiscussion(String title, long topic, User user) {
Discussion discussion = new Discussion();
discussion.setAuthor(user.getUsername());
discussion.setDate(new Date());
discussion.setTitle(title);
discussion.setTopic(topic);
discussion.setMessages(new ArrayList<>());
discussion.setLast_update(new Date());
discussion.setStatus(DiscussionStatus.OPEN);
discussion.setPinned(false);
discussionRepo.save(discussion);
}
public void editDiscussion(String title, long discussion_id, DiscussionStatus status, User user) {
Discussion discussion = discussionRepo.findById(discussion_id).orElseThrow();
if(!(discussion.getAuthor().equals(user.getUsername()) || user.isModer())) throw new SecurityException();
discussion.setAuthor(user.getUsername());
discussion.setTitle(title);
discussion.setLast_update(new Date());
discussion.setStatus(status);
discussionRepo.save(discussion);
}
public void addDiscussionMessage(String text, long discussion_id, User user) {
DiscussionMessage message = new DiscussionMessage();
message.setDate(new Date());
message.setEdited(false);
message.setSender(user.getUsername());
message.setText(text);
message.setDiscussion_id(discussion_id);
discussionMessageRepo.save(message);
Discussion discussion = discussionRepo.findById(discussion_id).orElseThrow();
List<Long> newMsgs = discussion.getMessages();
newMsgs.add(message.getId());
discussion.setMessages(newMsgs);
discussionRepo.save(discussion);
}
public void editDiscussionMessage(String text, long message_id, User user) {
DiscussionMessage message = discussionMessageRepo.findById(message_id).orElseThrow();
if(!(message.getSender().equals(user.getUsername()) || user.isAdmin())) throw new SecurityException();
message.setEdited(true);
message.setText(text);
discussionMessageRepo.save(message);
}
public void deleteDiscussionMessage(long message_id, User user) {
DiscussionMessage message = discussionMessageRepo.findById(message_id).orElseThrow();
if(!(message.getSender().equals(user.getUsername()) || user.isAdmin())) throw new SecurityException();
discussionMessageRepo.delete(message);
}
public DiscussionMessage getDiscussionMessageById(long id) {
return discussionMessageRepo.findById(id).orElseThrow();
}
}
@@ -0,0 +1,7 @@
package site.easystartup.web.service;
public class UserNotAuthenticatedException extends RuntimeException {
public UserNotAuthenticatedException() {
super("The user is not logged in to the system!");
}
}
@@ -1,7 +1,8 @@
package site.easystartup.web.service;
import lombok.RequiredArgsConstructor;
import org.hibernate.query.criteria.internal.predicate.PredicateImplementor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import site.easystartup.web.domain.User;
@@ -21,4 +22,12 @@ public class UserService {
public User getUserById(Long userId) {
return userRepo.findById(userId).orElseThrow(() -> new UsernameNotFoundException("User not found"));
}
public User getCurrentUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if(auth.isAuthenticated()) throw new UserNotAuthenticatedException();
org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User)
auth.getPrincipal();
return userRepo.findByUsername(user.getUsername());
}
}
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>403</title>
</head>
<body>
<p>You have hot permissions for this!</p>
</body>
</html>
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>403</title>
</head>
<body>
</body>
</html>
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>403</title>
</head>
<body>
</body>
</html>