Try to add topic pages
This commit is contained in:
1 parent
58e927cc87
commit
fd9d9579b0
10 files changed
+120
-55
No files matched your search
+2
-1
@@ -7,7 +7,7 @@ plugins {
|
|||||||
|
|
||||||
group = 'site.easy-startup'
|
group = 'site.easy-startup'
|
||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
sourceCompatibility = '8'
|
sourceCompatibility = "16"
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
compileOnly {
|
compileOnly {
|
||||||
@@ -42,3 +42,4 @@ dependencies {
|
|||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
targetCompatibility = JavaVersion.VERSION_16
|
||||||
@@ -11,7 +11,6 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
|||||||
@ComponentScan(basePackages = {"site.easystartup.easystartupcore"})
|
@ComponentScan(basePackages = {"site.easystartup.easystartupcore"})
|
||||||
public class AppConfig {
|
public class AppConfig {
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PasswordEncoder passwordEncoder() {
|
public PasswordEncoder passwordEncoder() {
|
||||||
return new BCryptPasswordEncoder();
|
return new BCryptPasswordEncoder();
|
||||||
|
|||||||
+47
-5
@@ -8,33 +8,75 @@ import org.springframework.security.core.userdetails.User;
|
|||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import site.easystartup.easystartupcore.forum.filter.FilterService;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import site.easystartup.easystartupcore.forum.domain.Topic;
|
||||||
|
import site.easystartup.easystartupcore.forum.filter.ForumFilterService;
|
||||||
import site.easystartup.easystartupcore.forum.repo.TopicRepo;
|
import site.easystartup.easystartupcore.forum.repo.TopicRepo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
public class ForumController {
|
public class ForumController {
|
||||||
private final TopicRepo topicRepo;
|
private final TopicRepo topicRepo;
|
||||||
|
|
||||||
private final FilterService filterService;
|
private final ForumFilterService forumFilterService;
|
||||||
|
|
||||||
@GetMapping("/forum")
|
@GetMapping("/forum")
|
||||||
public String forumMain(Model model) {
|
public String forumMain(Model model) {
|
||||||
val topic = topicRepo.findAll();
|
val topic = topicRepo.findAll();
|
||||||
model.addAttribute("topics", topic);
|
model.addAttribute("topics", topic);
|
||||||
return "forum";
|
return "/forum";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/forum/my")
|
@GetMapping("/forum/my")
|
||||||
public String forumMy(Model model) {
|
public String forumMy(Model model) {
|
||||||
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
val discussions = filterService.getDiscussionsByAuthor(user.getUsername());
|
val discussions = forumFilterService.getDiscussionsByAuthor(user.getUsername());
|
||||||
model.addAttribute("discussions", discussions);
|
model.addAttribute("discussions", discussions);
|
||||||
return "my-discussions";
|
return "/my-discussions";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/forum/new")
|
@GetMapping("/forum/new")
|
||||||
public String forumNew() {
|
public String forumNew() {
|
||||||
return "topic-new";
|
return "topic-new";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
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);
|
||||||
|
model.addAttribute("pinned_discussions", pinned_discussions);
|
||||||
|
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList(0, 15);
|
||||||
|
model.addAttribute("discussions", discussions);
|
||||||
|
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 pinned_discussions = forumFilterService.getPinnedDiscussionsByTopicId(topic_id);
|
||||||
|
model.addAttribute("pinned_discussions", pinned_discussions);
|
||||||
|
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList(0, 15);
|
||||||
|
model.addAttribute("discussions", discussions);
|
||||||
|
return "topic-first";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ import java.util.Objects;
|
|||||||
@ToString
|
@ToString
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Entity
|
@Entity
|
||||||
public class Discussion {
|
public class Discussion implements Comparable<Discussion>{
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
private long id;
|
private long id;
|
||||||
@@ -21,6 +21,9 @@ public class Discussion {
|
|||||||
private String author;
|
private String author;
|
||||||
private Date date;
|
private Date date;
|
||||||
private Date last_update;
|
private Date last_update;
|
||||||
|
private boolean pinned;
|
||||||
|
private DiscussionStatus status;
|
||||||
|
private long topic;
|
||||||
|
|
||||||
@ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER)
|
@ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER)
|
||||||
@CollectionTable(name = "discussion_messages", joinColumns = @JoinColumn(name = "discussion_id"))
|
@CollectionTable(name = "discussion_messages", joinColumns = @JoinColumn(name = "discussion_id"))
|
||||||
@@ -38,4 +41,11 @@ public class Discussion {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return getClass().hashCode();
|
return getClass().hashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Discussion o) {
|
||||||
|
if (getLast_update() == null || o.getLast_update() == null)
|
||||||
|
return 0;
|
||||||
|
return getLast_update().compareTo(o.getLast_update());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+16
-1
@@ -9,11 +9,12 @@ import site.easystartup.easystartupcore.forum.domain.DiscussionMessage;
|
|||||||
import site.easystartup.easystartupcore.forum.repo.DiscussionMessageRepo;
|
import site.easystartup.easystartupcore.forum.repo.DiscussionMessageRepo;
|
||||||
import site.easystartup.easystartupcore.forum.repo.DiscussionRepo;
|
import site.easystartup.easystartupcore.forum.repo.DiscussionRepo;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
public class FilterService {
|
public class ForumFilterService {
|
||||||
private final DiscussionMessageRepo discussionMessageRepo;
|
private final DiscussionMessageRepo discussionMessageRepo;
|
||||||
|
|
||||||
private final DiscussionRepo discussionRepo;
|
private final DiscussionRepo discussionRepo;
|
||||||
@@ -33,4 +34,18 @@ public class FilterService {
|
|||||||
.filter(d -> getMessagesByDiscussionId(d.getId()).stream()
|
.filter(d -> getMessagesByDiscussionId(d.getId()).stream()
|
||||||
.anyMatch(m -> m.getSender().equals(member))).toList();
|
.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,5 @@ spring.sql.init.mode=always
|
|||||||
spring.sql.init.platform=postgres
|
spring.sql.init.platform=postgres
|
||||||
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
|
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
|
||||||
spring.datasource.username=postgres
|
spring.datasource.username=postgres
|
||||||
#spring.datasource.password=root
|
spring.datasource.password=root
|
||||||
spring.datasource.password=postgres
|
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<h1>Пожалуйста, войдите</h1>
|
<h1>Пожалуйста, войдите</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input type="text" class="form-control" minlength="3" size="25" id="username" name="username" required placeholder="UserName">
|
<input type="text" minlength="3" size="25" id="username" name="username" required placeholder="UserName">
|
||||||
<label for="username">Логин</label>
|
<label for="username">Логин</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -6,18 +6,6 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Вход</title>
|
<title>Вход</title>
|
||||||
|
|
||||||
<style>
|
|
||||||
div.error {
|
|
||||||
color: #ff5967;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.logout {
|
|
||||||
color: #2c84ec;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
@@ -28,7 +16,7 @@
|
|||||||
<p>Мои обсуждения</p>
|
<p>Мои обсуждения</p>
|
||||||
<div th:each="el : ${discussions}">
|
<div th:each="el : ${discussions}">
|
||||||
<h2 th:text="${el.title}"/>
|
<h2 th:text="${el.title}"/>
|
||||||
<p th:text="'Автор: ' + ${el.title}"/>
|
<p th:text="'Автор: ' + ${el.author}"/>
|
||||||
<p th:text="'Дата создания: ' + ${#dates.format(el.date, 'hh:mm dd MMM yyyy')}"/>
|
<p th:text="'Дата создания: ' + ${#dates.format(el.date, 'hh:mm dd MMM yyyy')}"/>
|
||||||
<p th:text="'Последнее обновление: ' + ${#dates.format(el.last_update, 'hh:mm dd MMM yyyy')}"/>
|
<p th:text="'Последнее обновление: ' + ${#dates.format(el.last_update, 'hh:mm dd MMM yyyy')}"/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org"
|
||||||
|
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Вход</title>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
<h2>Закреплённые сообщения</h2>
|
||||||
|
<div th:each="el : ${pinned_discussions}">
|
||||||
|
<h2 th:text="${el.title}"/>
|
||||||
|
<p th:text="'Автор: ' + ${el.author}"/>
|
||||||
|
<p th:text="'Дата создания: ' + ${#dates.format(el.date, 'hh:mm dd MMM yyyy')}"/>
|
||||||
|
<p th:text="'Последнее обновление: ' + ${#dates.format(el.last_update, 'hh:mm dd MMM yyyy')}"/>
|
||||||
|
</div>
|
||||||
|
<h2>Остальные сообщения</h2>
|
||||||
|
<div th:each="el : ${discussions}">
|
||||||
|
<h2 th:text="${el.title}"/>
|
||||||
|
<p th:text="'Автор: ' + ${el.author}"/>
|
||||||
|
<p th:text="'Дата создания: ' + ${#dates.format(el.date, 'hh:mm dd MMM yyyy')}"/>
|
||||||
|
<p th:text="'Последнее обновление: ' + ${#dates.format(el.last_update, 'hh:mm dd MMM yyyy')}"/>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -3,20 +3,8 @@
|
|||||||
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
|
xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Вход</title>
|
<title>Новая тема</title>
|
||||||
|
|
||||||
<style>
|
|
||||||
div.error {
|
|
||||||
color: #ff5967;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.logout {
|
|
||||||
color: #2c84ec;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
@@ -29,28 +17,16 @@
|
|||||||
<h1>Пожалуйста, введите данные новой темы</h1>
|
<h1>Пожалуйста, введите данные новой темы</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<input type="text" class="form-control" minlength="3" size="25" id="username" name="username" required placeholder="UserName">
|
<input type="text" name="title" id="title" size="3" maxlength="15" required placeholder="Новая тема">
|
||||||
<label for="username">Логин</label>
|
<label for="title">Титул</label>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input type="password" name="password" minlength="3" id="password" required placeholder="Password123">
|
<input type="text" name="description" id="description" placeholder="Описание">
|
||||||
<label for="password">Пароль</label>
|
<label for="description">Описание</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<button type="submit">Создать тему</button>
|
||||||
<label>
|
|
||||||
<input type="checkbox" name="remember-me"> Запомнить меня
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Войти</button>
|
|
||||||
|
|
||||||
<div th:if="${param.error}" class="error">
|
|
||||||
Неправильный логин или пароль.
|
|
||||||
</div>
|
|
||||||
<div th:if="${param.logout}" class="logout">
|
|
||||||
Вы вышли из аккаунта.
|
|
||||||
</div>
|
|
||||||
<input type="hidden" name="_csrf" th:value="${_csrf.token}">
|
<input type="hidden" name="_csrf" th:value="${_csrf.token}">
|
||||||
<p>© 2022</p>
|
<p>© 2022</p>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in new issue
Block a user