posts & topics
This commit is contained in:
parent
a038eba691
commit
89c76406ea
@ -1,7 +1,10 @@
|
||||
package com.webproglabs.lab1.dao;
|
||||
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.Topic;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -9,4 +12,7 @@ import java.util.Optional;
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
List<Post> findByTextLike(String text);
|
||||
Optional<Post> findById(Long Id);
|
||||
|
||||
@Query("SELECT p FROM Post p WHERE p.topic = :topic AND p.text LIKE %:text%")
|
||||
List<Post> findPostsByTextInTopic(@Param("text") String text, @Param("topic") Topic topic);
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
package com.webproglabs.lab1.dao;
|
||||
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.Topic;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface TopicRepository extends JpaRepository<Topic, Long> {
|
||||
Optional<Topic> findById(Long Id);
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public class TopicDto {
|
||||
posts.add(new PostDto(post));
|
||||
}
|
||||
}
|
||||
public TopicDto(){}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
@ -22,6 +22,7 @@ public class Topic {
|
||||
this.description = description;
|
||||
this.posts = new ArrayList<Post>();
|
||||
}
|
||||
public Topic(){}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
@ -0,0 +1,97 @@
|
||||
package com.webproglabs.lab1.mvc;
|
||||
|
||||
import com.webproglabs.lab1.dto.PostDto;
|
||||
import com.webproglabs.lab1.dto.TopicDto;
|
||||
import com.webproglabs.lab1.dto.UserDto;
|
||||
import com.webproglabs.lab1.services.CommentService;
|
||||
import com.webproglabs.lab1.services.PostService;
|
||||
import com.webproglabs.lab1.services.TopicService;
|
||||
import com.webproglabs.lab1.services.UserService;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/feed")
|
||||
public class FeedMvcController {
|
||||
private final UserService userService;
|
||||
private final PostService postService;
|
||||
private final CommentService commentService;
|
||||
private final TopicService topicService;
|
||||
|
||||
public FeedMvcController(UserService userService, PostService postService, CommentService commentService, TopicService topicService) {
|
||||
this.userService = userService;
|
||||
this.postService = postService;
|
||||
this.commentService = commentService;
|
||||
this.topicService = topicService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String getFeedPage(Model model) {
|
||||
model.addAttribute("topics", topicService.findAllTopics().stream().map(TopicDto::new).toList());
|
||||
return "feed";
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/{id}"})
|
||||
public String getFeedPageWithTopic(@PathVariable Long id, Model model) {
|
||||
model.addAttribute("profiles", userService.findAllUsers().stream().map(UserDto::new).toList());
|
||||
model.addAttribute("posts", topicService.findTopicById(id).getPosts().stream().map(PostDto::new).toList());
|
||||
model.addAttribute("topics", topicService.findAllTopics().stream().map(TopicDto::new).toList());
|
||||
|
||||
UserDetails principal = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var user = userService.findUserByLogin(principal.getUsername());
|
||||
model.addAttribute("selectedProfile", new UserDto(userService.findUserById(user.getId())));
|
||||
|
||||
model.addAttribute("selectedTopic", new TopicDto(topicService.findTopicById(id)));
|
||||
|
||||
return "feedPosts";
|
||||
}
|
||||
|
||||
@GetMapping(value= {"/filter/{id}/"})
|
||||
public String getFeedPageFiltered(@PathVariable Long id, @RequestParam(value="searchField") String searchField, Model model) {
|
||||
model.addAttribute("profiles", userService.findAllUsers().stream().map(UserDto::new).toList());
|
||||
model.addAttribute("topics", topicService.findAllTopics().stream().map(TopicDto::new).toList());
|
||||
UserDetails principal = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var user = userService.findUserByLogin(principal.getUsername());
|
||||
model.addAttribute("selectedProfile", new UserDto(userService.findUserById(user.getId())));
|
||||
model.addAttribute("selectedTopic", new TopicDto(topicService.findTopicById(id)));
|
||||
|
||||
model.addAttribute("posts", postService.findPostsInTopicByText(searchField, id).stream().map(PostDto::new).toList());
|
||||
|
||||
return "feedPosts";
|
||||
}
|
||||
|
||||
@PostMapping(value={"/{topicId}/post/{id}/"})
|
||||
public String createPost(@PathVariable Long topicId, @PathVariable Long id, @RequestParam(value="postInputField") String postInputField) {
|
||||
postService.addPost(postInputField, id, topicId);
|
||||
return "redirect:/feed/" + topicId.toString();
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/deletePost/{id}/{topicId}"})
|
||||
public String deletePost(@PathVariable Long id, @PathVariable Long topicId) {
|
||||
postService.deletePost(id);
|
||||
return "redirect:/feed/" + topicId.toString();
|
||||
}
|
||||
|
||||
@GetMapping(value = {"postModal/{id}/{topicId}"})
|
||||
public String getPostEditModal(@PathVariable Long id,@PathVariable Long topicId, Model model) {
|
||||
model.addAttribute("selectedPost", new PostDto(postService.findPostById(id)));
|
||||
model.addAttribute("profiles", userService.findAllUsers().stream().map(UserDto::new).toList());
|
||||
model.addAttribute("posts", topicService.findTopicById(topicId).getPosts().stream().map(PostDto::new).toList());
|
||||
|
||||
UserDetails principal = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var user = userService.findUserByLogin(principal.getUsername());
|
||||
model.addAttribute("selectedProfile", new UserDto(userService.findUserById(user.getId())));
|
||||
model.addAttribute("selectedTopic", new TopicDto(topicService.findTopicById(topicId)));
|
||||
return "editPostModal";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"editPost/{id}/{topicId}/"})
|
||||
public String editPost(@PathVariable Long id, @PathVariable Long topicId, @RequestParam(value="postEditField") String postEditField) {
|
||||
postService.updatePost(id, postEditField);
|
||||
return "redirect:/feed/" + topicId.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.webproglabs.lab1.mvc;
|
||||
|
||||
import com.webproglabs.lab1.dto.TopicDto;
|
||||
import com.webproglabs.lab1.dto.UserSignupDto;
|
||||
import com.webproglabs.lab1.models.UserRole;
|
||||
import com.webproglabs.lab1.services.TopicService;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/topic")
|
||||
public class TopicMvcController {
|
||||
private final TopicService topicService;
|
||||
|
||||
public TopicMvcController(TopicService topicService) {
|
||||
this.topicService = topicService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String getTopics(Model model) {
|
||||
model.addAttribute("topics", topicService.findAllTopics().stream().map(TopicDto::new).toList());
|
||||
model.addAttribute("topicDto", new TopicDto());
|
||||
return "topics";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/create"})
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String createTopic(@ModelAttribute TopicDto topicDto) {
|
||||
topicService.addTopic(topicDto.getName(), topicDto.getDescription());
|
||||
return "redirect:/topic";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/delete/{Id}"})
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String deleteTopic(@PathVariable Long Id) {
|
||||
topicService.deleteTopic(Id);
|
||||
return "redirect:/topic";
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/edit/{Id}"})
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String getTopicEdit(@PathVariable Long Id, Model model) {
|
||||
model.addAttribute("topic", new TopicDto(topicService.findTopicById(Id)));
|
||||
model.addAttribute("topicDto", new TopicDto(topicService.findTopicById(Id)));
|
||||
return "topicEdit";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/edit/{Id}"})
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String editTopic(@PathVariable Long Id, @ModelAttribute TopicDto topicDto) {
|
||||
topicService.updateTopic(Id, topicDto.getName(), topicDto.getDescription());
|
||||
return "redirect:/topic";
|
||||
}
|
||||
|
||||
}
|
@ -57,6 +57,12 @@ public class PostService {
|
||||
return postList;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Post> findPostsInTopicByText(String text, Long topicId) {
|
||||
Topic topic = topicRepository.findById(topicId).get();
|
||||
return postRepository.findPostsByTextInTopic(text, topic);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Post addPost (String text, Long authorId, Long topicId) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
|
@ -24,10 +24,10 @@
|
||||
</div>
|
||||
<div>
|
||||
<p class='h4 text-center'>
|
||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/topic" class="text-decoration-none m-3">Топики</a>
|
||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/users" class="text-decoration-none m-3">Пользователи</a>
|
||||
<a sec:authorize="isAuthenticated()" href="/feed" class="text-decoration-none m-3">Лента</a>
|
||||
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3">
|
||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/topic" class="text-decoration-none m-3 text-secondary">Топики</a>
|
||||
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/users" class="text-decoration-none m-3 text-secondary">Пользователи</a>
|
||||
<a sec:authorize="isAuthenticated()" href="/feed" class="text-decoration-none m-3 text-secondary">Лента</a>
|
||||
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3 text-secondary">
|
||||
Выход
|
||||
</a>
|
||||
</p>
|
||||
@ -37,5 +37,12 @@
|
||||
<div layout:fragment="content"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
window.onload = () => {
|
||||
$('#postEdit').modal('show');
|
||||
$('#commentCreate').modal('show');
|
||||
$('#commentEdit').modal('show');
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
32
src/main/resources/templates/editPostModal.html
Normal file
32
src/main/resources/templates/editPostModal.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{feedPosts}" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div layout:fragment="modalFeed">
|
||||
|
||||
<div class="modal fade" id="postEdit" tabindex="-1" role="dialog" aria-labelledby="postEditLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="postEditLabel">Редактировать пост</h5>
|
||||
</div>
|
||||
<form th:action="@{/feed/editPost/{id}/{topicId}/{text} (id=${selectedPost.id}, topicId=${selectedTopic.id}, text=${postEditField} ) }" method="post" class="modal-body text-center">
|
||||
<p>Текст поста:</p>
|
||||
<input th:attr="value = ${selectedPost.text}" id="postEditField" name="postEditField" type="text" class="mb-2">
|
||||
<br>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="submit" class="btn btn-primary" >Сохранить</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
32
src/main/resources/templates/feed.html
Normal file
32
src/main/resources/templates/feed.html
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{default}">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<div class="text-center">
|
||||
<div class="dropdown text-center mx-auto w-75">
|
||||
<div class="text-center mt-3">
|
||||
<button class="btn btn-secondary dropdown-toggle ms-3 mb-3 w-50" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Выбор топика
|
||||
</button>
|
||||
<ul class="dropdown-menu w-50" >
|
||||
<li th:each="topic: ${topics}">
|
||||
<a class="dropdown-item" th:href="@{/feed/{id}(id=${topic.id})}" th:text="${topic.name + '. ' + topic.description}">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div layout:fragment="contentFeed"></div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
107
src/main/resources/templates/feedPosts.html
Normal file
107
src/main/resources/templates/feedPosts.html
Normal file
@ -0,0 +1,107 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{feed}" xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="contentFeed">
|
||||
|
||||
<div class='h3 mb-3 mx-auto w-75'>
|
||||
<p class="text-center h3" th:text="${selectedTopic.name}"></p>
|
||||
<p class="text-end" th:text="${selectedProfile.login}"></p>
|
||||
</div>
|
||||
<div class='h3 m-3 d-flex justify-content-between text-center mx-auto w-75'>
|
||||
|
||||
Лента
|
||||
<button type='button' class="btn btn-primary ms-5 mb-3 " data-bs-toggle="modal" data-bs-target="#postCreate">
|
||||
Добавить новый пост
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form th:action="@{/feed/filter/{id}/{text} (id=${selectedTopic.id}, text=${searchField}) }" method="get">
|
||||
<input th:value="${searchField}" id="searchField" name="searchField" type="text" class="mb-2" style="width: 70%" placeholder="Поиск...">
|
||||
<button type='submit' class="btn btn-primary mb-2" style="width: 5%">
|
||||
Найти
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
||||
<div th:each="post: ${posts}" class="text-center mx-auto w-75 mb-3 ">
|
||||
<div class="border p-2">
|
||||
<p th:text="${post.text}" class="h4 text-start"></p>
|
||||
<div class="d-flex justify-content-between fst-italic">
|
||||
<div>
|
||||
Автор:
|
||||
<a th:text="${post.getAuthor()}" class="text-start fst-italic" th:href="@{/profile/{login}(login=${post.getAuthor()})}"></a>
|
||||
</div>
|
||||
<div th:if="${selectedProfile.getLogin() == post.getAuthor()}" class="d-flex justify-content-between fst-italic">
|
||||
<form th:action="@{/feed/deletePost/{id}/{topicId} (id=${post.id}, topicId=${selectedTopic.id})}" method="post" >
|
||||
<button type="submit" class="btn btn-danger me-1 mb-1 ms-2" >
|
||||
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
<form th:action="@{/feed/postModal/{id}/{topicId} (id=${post.id}, topicId=${selectedTopic.id})}" method="get">
|
||||
<button type="submit" class="btn btn-warning mb-1" data-bs-toggle="modal" data-bs-target="#postEdit" >
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border p-2" th:if="${post.comments.size() > 0}" >
|
||||
<div class="text-start">
|
||||
<p class="text-start h5">Комментарии:</p>
|
||||
<div th:each="comment: ${post.comments}" >
|
||||
<p class="fst-italic" th:text="${comment.getAuthor() + ':'}"> </p>
|
||||
<div class="d-flex justify-content-between fst-italic">
|
||||
<p class="ms-3" th:text="${comment.text}"></p>
|
||||
|
||||
<div th:if="${selectedProfile.getLogin() == comment.getAuthor()}" class="d-flex justify-content-between fst-italic">
|
||||
<form th:action="@{/feed/deleteComment/{id}/{authorId} (id=${comment.id}, authorId=${selectedProfile.id})}" method="post" >
|
||||
<button type="submit" class="btn btn-danger me-1 mb-1"> <i class="fa fa-trash" aria-hidden="true"> </i> </button>
|
||||
</form>
|
||||
<form th:action="@{/feed/commentEditModal/{id}/{authorId} (id=${comment.id}, authorId=${selectedProfile.id})}" method="get">
|
||||
<button type="submit" class="btn btn-warning mb-1" data-bs-toggle="modal" data-bs-target="#postEdit" >
|
||||
<i class="fa fa-pencil" aria-hidden="true"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form th:action="@{/feed/commentModal/{authorId}/{postId}/ ( authorId=${selectedProfile.id}, postId=${post.id} ) }" method="get" class="text-end">
|
||||
<button type="submit" class="btn btn-info mb-3" data-bs-toggle="modal" data-bs-target="#commentCreate">Добавить комментарий</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="postCreate" tabindex="-1" role="dialog" aria-labelledby="postCreateLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="postCreateLabel">Создать пост</h5>
|
||||
</div>
|
||||
<form th:action="@{/feed/{topicId}/post/{id}/{text} (topicId=${selectedTopic.id}, id=${selectedProfile.id}, text=${postInputField}) }" method="post" class="modal-body text-center">
|
||||
<p>Текст поста:</p>
|
||||
<input th:value="${postInputField}" id="postInputField" name="postInputField" type="text" class="mb-2">
|
||||
<br>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
|
||||
<button type="submit" class="btn btn-primary" >Сохранить</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div layout:fragment="modalFeed"></div>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,4 +1,3 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
|
19
src/main/resources/templates/topicEdit.html
Normal file
19
src/main/resources/templates/topicEdit.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{default}"
|
||||
xmlns:th="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<div class="container container-padding" layout:fragment="content">
|
||||
<div class="h4 text-center">Изменить топик</div>
|
||||
<form action="#" th:action="@{/topic/edit/{id} (id=${topic.id})}" th:object="${topicDto}" method="post">
|
||||
<p>Новое название:</p>
|
||||
<input th:field="${topicDto.name}" type="text" class="mb-2 form-control" required="true" />
|
||||
<p>Новое описание:</p>
|
||||
<input th:field="${topicDto.description}" type="text" class="mb-2 form-control" required="true" />
|
||||
<button type="submit" class="btn btn-success" >Сохранить изменения</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
32
src/main/resources/templates/topics.html
Normal file
32
src/main/resources/templates/topics.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{default}">
|
||||
<body>
|
||||
<div class="container container-padding" layout:fragment="content">
|
||||
|
||||
<form action="#" th:action="@{/topic/create}" th:object="${topicDto}" method="post">
|
||||
<p>Название:</p>
|
||||
<input th:field="${topicDto.name}" type="text" class="mb-2 form-control" required="true" />
|
||||
<p>Описание:</p>
|
||||
<input th:field="${topicDto.description}" type="text" class="mb-2 form-control" required="true" />
|
||||
<button type="submit" class="btn btn-success">Добавить</button>
|
||||
</form>
|
||||
|
||||
<div th:each="topic: ${topics}" class="border p-3 m-3 shadow-lg bg-body rounded">
|
||||
<div th:text="${'Топик: ' + topic.name}"></div>
|
||||
<div th:text="${'Описание: ' + topic.description}"></div>
|
||||
<form action="#" th:action="@{/topic/edit/{id} (id=${topic.id})}" method="get" class="text-end m-1">
|
||||
<button type="submit" class="btn btn-warning">Изменить</button>
|
||||
</form>
|
||||
<form action="#" th:action="@{/topic/delete/{id} (id=${topic.id})}" method="post" class="text-end m-1">
|
||||
<button type="submit" class="btn btn-danger" >Удалить</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user