- Добавил возможность подписаться на пользователя и отписаться от него.
- Добавил вывод списка подписчиков/подписок. https://www.youtube.com/watch?v=JpF0MwdJzO4&list=PLU2ftbIeotGpAYRP9Iv2KLIwK36-o_qYk&index=19
This commit is contained in:
@@ -68,4 +68,38 @@ public class UserController {
|
||||
customUserDetailsService.updateProfile(customUserDetails.getUser(), password, email);
|
||||
return "redirect:/users/profile";
|
||||
}
|
||||
|
||||
@GetMapping("/{type}/{user}/list")
|
||||
public String getSubscribtions(@PathVariable User user,
|
||||
@PathVariable String type,
|
||||
Model model) {
|
||||
model.addAttribute("userChannel", user);
|
||||
model.addAttribute("type", type);
|
||||
|
||||
if ("subscribers".equals(type)) {
|
||||
model.addAttribute("users", user.getSubscribers());
|
||||
} else if ("subscriptions".equals(type)) {
|
||||
model.addAttribute("users", user.getSubscribtions());
|
||||
}
|
||||
|
||||
return "subscriptions";
|
||||
}
|
||||
|
||||
@GetMapping("/subscribe/{user}")
|
||||
public String subscribe(@AuthenticationPrincipal CustomUserDetails customUserDetails,
|
||||
@PathVariable User user) {
|
||||
|
||||
User currentUser = customUserDetails.getUser();
|
||||
customUserDetailsService.subscribe(currentUser, user);
|
||||
return "redirect:/user-messages/" + user.getId();
|
||||
}
|
||||
|
||||
@GetMapping("/unsubscribe/{user}")
|
||||
public String unsubscribe(@AuthenticationPrincipal CustomUserDetails customUserDetails,
|
||||
@PathVariable User user) {
|
||||
|
||||
User currentUser = customUserDetails.getUser();
|
||||
customUserDetailsService.unsubscribe(currentUser, user);
|
||||
return "redirect:/user-messages/" + user.getId();
|
||||
}
|
||||
}
|
||||
@@ -39,31 +39,35 @@ public class UserMessagesController {
|
||||
model.addAttribute("isCurrentUser", user.equals(currentUser));
|
||||
model.addAttribute("messages", user.getMessages());
|
||||
model.addAttribute("message", message);
|
||||
model.addAttribute("userChannel", user);
|
||||
model.addAttribute("subscribersCount", user.getSubscribers().size());
|
||||
model.addAttribute("subscriptionsCount", user.getSubscribtions().size());
|
||||
model.addAttribute("isSubscriber", user.getSubscribers().contains(currentUser));
|
||||
|
||||
return "user_messages";
|
||||
}
|
||||
|
||||
@PostMapping("/user-messages/{userId}")
|
||||
public String getUserMessages(@AuthenticationPrincipal CustomUserDetails customUserDetails,
|
||||
@PathVariable(name = "userId") Long userId,
|
||||
@RequestParam(required = false) Message message,
|
||||
@RequestParam String text,
|
||||
@RequestParam String tag,
|
||||
@RequestParam("file") MultipartFile file
|
||||
public String getUserMessage(@AuthenticationPrincipal CustomUserDetails customUserDetails,
|
||||
@PathVariable(name = "userId") Long userId,
|
||||
@ModelAttribute Message message,
|
||||
@RequestParam String text,
|
||||
@RequestParam String tag,
|
||||
@RequestParam("file") MultipartFile file
|
||||
) throws IOException {
|
||||
|
||||
User currentUser = customUserDetails.getUser();
|
||||
if (message.getAuthor().equals(currentUser)) {
|
||||
if (!ObjectUtils.isEmpty(text)) {
|
||||
message.setText(text);
|
||||
}
|
||||
message.setAuthor(customUserDetails.getUser());
|
||||
|
||||
if (!ObjectUtils.isEmpty(tag)) {
|
||||
message.setTag(tag);
|
||||
}
|
||||
|
||||
ControllerUtils.saveFile(message, file, uploadPath);
|
||||
messageRepository.save(message);
|
||||
if (!ObjectUtils.isEmpty(text)) {
|
||||
message.setText(text);
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(tag)) {
|
||||
message.setTag(tag);
|
||||
}
|
||||
|
||||
ControllerUtils.saveFile(message, file, uploadPath);
|
||||
messageRepository.save(message);
|
||||
return "redirect:/user-messages/" + userId;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -38,6 +39,15 @@ public class User implements Serializable {
|
||||
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private Set<Message> messages;
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "user_subscriptions", joinColumns = { @JoinColumn(name = "channel_id")},
|
||||
inverseJoinColumns = { @JoinColumn(name = "subscriber_id")})
|
||||
private Set<User> subscribers = new HashSet<>();
|
||||
|
||||
@ManyToMany
|
||||
@JoinTable(name = "user_subscriptions", joinColumns = { @JoinColumn(name = "subscriber_id")},
|
||||
inverseJoinColumns = { @JoinColumn(name = "channel_id")})
|
||||
private Set<User> subscribtions = new HashSet<>();
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -126,4 +136,20 @@ public class User implements Serializable {
|
||||
public void setMessages(Set<Message> messages) {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public Set<User> getSubscribers() {
|
||||
return subscribers;
|
||||
}
|
||||
|
||||
public void setSubscribers(Set<User> subscribers) {
|
||||
this.subscribers = subscribers;
|
||||
}
|
||||
|
||||
public Set<User> getSubscribtions() {
|
||||
return subscribtions;
|
||||
}
|
||||
|
||||
public void setSubscribtions(Set<User> subscribtions) {
|
||||
this.subscribtions = subscribtions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ public class CustomUserDetailsService implements UserDetailsService {
|
||||
}
|
||||
|
||||
private void sendMessage(User user) {
|
||||
|
||||
if (!ObjectUtils.isEmpty(user.getEmail())) {
|
||||
|
||||
String message = String.format(
|
||||
@@ -133,6 +134,19 @@ public class CustomUserDetailsService implements UserDetailsService {
|
||||
}
|
||||
|
||||
public List<User> findAll() {
|
||||
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
public void subscribe(User currentUser, User user) {
|
||||
|
||||
user.getSubscribers().add(currentUser);
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
public void unsubscribe(User currentUser, User user) {
|
||||
|
||||
user.getSubscribers().remove(currentUser);
|
||||
userRepository.save(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
create table if not exists user_subscriptions
|
||||
(
|
||||
channel_id bigint not null references usr,
|
||||
subscriber_id bigint not null references usr,
|
||||
primary key (channel_id, subscriber_id),
|
||||
FOREIGN KEY (channel_id) REFERENCES usr(id),
|
||||
FOREIGN KEY (subscriber_id) REFERENCES usr(id)
|
||||
) engine = InnoDB;
|
||||
@@ -1,3 +1,4 @@
|
||||
<#include "security.ftl">
|
||||
<#macro login path isRegistrationForm=false>
|
||||
<form action="${path}" method="post" xmlns="http://www.w3.org/1999/html">
|
||||
<div class="row mb-3">
|
||||
@@ -74,6 +75,6 @@
|
||||
<#macro logout>
|
||||
<form action="/logout" method="post">
|
||||
<input type="hidden" name="_csrf" value="${_csrf.token}"/>
|
||||
<button type="submit" class="btn btn-primary">Sign Out</button>
|
||||
<button class="btn btn-primary" type="submit"><#if user??>Sign Out<#else>Log in</#if></button>
|
||||
</form>
|
||||
</#macro>
|
||||
@@ -1,4 +1,6 @@
|
||||
<a class="btn btn-primary mb-3" data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false"
|
||||
<#include "security.ftl">
|
||||
|
||||
<a class="btn btn-primary mb-2" data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false"
|
||||
aria-controls="collapseExample">
|
||||
Message editor
|
||||
</a>
|
||||
@@ -30,7 +32,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" name="_csrf" value="${_csrf.token}"/>
|
||||
<input type="hidden" name="message-id" value=<#if message??>${message.id}</#if>/>
|
||||
<input type="hidden" name="id" value="<#if message??>${message.id}</#if>" />
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary">Save message</button>
|
||||
</div>
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="/">Home</a>
|
||||
</li>
|
||||
<#if user??>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="/main">Messages</a>
|
||||
</li>
|
||||
<#if user??>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" aria-current="page" href="/user-messages/${currentUserId}">My messages</a>
|
||||
</li>
|
||||
@@ -34,7 +34,7 @@
|
||||
</#if>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-text mr-3">${name}</div>
|
||||
<div><#if name != "unknown"> <@l.logout /> </#if></div>
|
||||
<div class="navbar-text mr-3"><#if user??>${name}<#else>Please, login</#if></div>
|
||||
<@l.logout />
|
||||
</div>
|
||||
</nav>
|
||||
12
src/main/resources/templates/subscriptions.ftl
Normal file
12
src/main/resources/templates/subscriptions.ftl
Normal file
@@ -0,0 +1,12 @@
|
||||
<#import "parts/common.ftl" as com>
|
||||
<@com.page>
|
||||
<h3>${userChannel.username}</h3>
|
||||
<div>${type}</div>
|
||||
<ul class="list-group">
|
||||
<#list users as user>
|
||||
<li class="list-group-item">
|
||||
<a href="/user-messages/${user.id}">${user.getUsername()}</a>
|
||||
</li>
|
||||
</#list>
|
||||
</ul>
|
||||
</@com.page>
|
||||
@@ -1,5 +1,39 @@
|
||||
<#import "parts/common.ftl" as com>
|
||||
<@com.page>
|
||||
<h3>${userChannel.username}</h3>
|
||||
<#if !isCurrentUser>
|
||||
<div class="form-group">
|
||||
<#if isSubscriber>
|
||||
<a class="btn btn-info" href="/users/unsubscribe/${userChannel.id}">Unsubscibe</a>
|
||||
<#else>
|
||||
<a class="btn btn-info" href="/users/subscribe/${userChannel.id}">Subscribe</a>
|
||||
</#if>
|
||||
</div>
|
||||
</#if>
|
||||
<div class="container my-2">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Subscriptions</div>
|
||||
<h3 class="card-text">
|
||||
<a href="/users/subscriptions/${userChannel.id}/list">${subscriptionsCount}</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title">Subscribers</div>
|
||||
<h3 class="card-text">
|
||||
<a href="/users/subscribers/${userChannel.id}/list">${subscribersCount}</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<#if isCurrentUser>
|
||||
<#include "parts/messageEditor.ftl">
|
||||
</#if>
|
||||
|
||||
Reference in New Issue
Block a user