Compare commits
9 Commits
8ae10007bb
...
794388d0f6
Author | SHA1 | Date | |
---|---|---|---|
794388d0f6 | |||
e42408413a | |||
71dd9b4fde | |||
263182db1d | |||
89c76406ea | |||
a038eba691 | |||
072a9514b6 | |||
db18f20ff6 | |||
e656fe0664 |
BIN
data.mv.db
BIN
data.mv.db
Binary file not shown.
3828
data.trace.db
3828
data.trace.db
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,8 @@
|
||||
package com.webproglabs.lab1;
|
||||
|
||||
import com.webproglabs.lab1.models.UserRole;
|
||||
import com.webproglabs.lab1.mvc.UserSignupMvcController;
|
||||
import com.webproglabs.lab1.services.UserService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -29,47 +32,47 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
|
||||
private static final String LOGIN_URL = "/login";
|
||||
public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
|
||||
// private final ProfileService userService;
|
||||
//
|
||||
// public SecurityConfiguration(ProfileService userService) {
|
||||
// this.userService = userService;
|
||||
// createAdminOnStartup();
|
||||
// }
|
||||
private final UserService userService;
|
||||
|
||||
// private void createAdminOnStartup() {
|
||||
// final String admin = "admin";
|
||||
// if (userService.findByLogin(admin) == null) {
|
||||
// log.info("Admin user successfully created");
|
||||
// try {
|
||||
// userService.createUser(admin, admin, admin, UserRole.ADMIN);
|
||||
// } catch (Exception e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
public SecurityConfiguration(UserService userService) {
|
||||
this.userService = userService;
|
||||
createAdminOnStartup();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void configure(HttpSecurity http) throws Exception {
|
||||
//
|
||||
// http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
|
||||
// http.headers().frameOptions().sameOrigin().and()
|
||||
// .cors().and()
|
||||
// .csrf().disable()
|
||||
// .authorizeRequests()
|
||||
// .antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll()
|
||||
// .antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
|
||||
// .anyRequest().authenticated()
|
||||
// .and()
|
||||
// .formLogin()
|
||||
// .loginPage(LOGIN_URL).permitAll()
|
||||
// .and()
|
||||
// .logout().permitAll();
|
||||
// }
|
||||
private void createAdminOnStartup() {
|
||||
final String admin = "admin";
|
||||
if (userService.findUserByLogin(admin) == null) {
|
||||
log.info("Admin user successfully created");
|
||||
try {
|
||||
userService.createUser(admin, admin, admin, UserRole.ADMIN);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// auth.userDetailsService(userService);
|
||||
// }
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
|
||||
http.headers().frameOptions().sameOrigin().and()
|
||||
.cors().and()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll()
|
||||
.antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage(LOGIN_URL).permitAll()
|
||||
.and()
|
||||
.logout().permitAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.userDetailsService(userService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
|
@ -0,0 +1,12 @@
|
||||
package com.webproglabs.lab1.dao;
|
||||
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CommentRepository extends JpaRepository<Comment, Long> {
|
||||
List<Comment> findByTextLike(String text);
|
||||
Optional<Comment> findById(Long Id);
|
||||
}
|
18
src/main/java/com/webproglabs/lab1/dao/PostRepository.java
Normal file
18
src/main/java/com/webproglabs/lab1/dao/PostRepository.java
Normal file
@ -0,0 +1,18 @@
|
||||
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 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);
|
||||
}
|
15
src/main/java/com/webproglabs/lab1/dao/TopicRepository.java
Normal file
15
src/main/java/com/webproglabs/lab1/dao/TopicRepository.java
Normal file
@ -0,0 +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);
|
||||
|
||||
}
|
12
src/main/java/com/webproglabs/lab1/dao/UserRepository.java
Normal file
12
src/main/java/com/webproglabs/lab1/dao/UserRepository.java
Normal file
@ -0,0 +1,12 @@
|
||||
package com.webproglabs.lab1.dao;
|
||||
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
Optional<User> findOneByLoginIgnoreCase(String login);
|
||||
Optional<User> findById(Long Id);
|
||||
}
|
30
src/main/java/com/webproglabs/lab1/dto/CommentDto.java
Normal file
30
src/main/java/com/webproglabs/lab1/dto/CommentDto.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.webproglabs.lab1.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class CommentDto {
|
||||
private Long id;
|
||||
@NotBlank
|
||||
private String text;
|
||||
@NotBlank
|
||||
private String authorLogin;
|
||||
|
||||
public CommentDto(Comment comment) {
|
||||
this.id = comment.getId();
|
||||
this.text = comment.getText();
|
||||
this.authorLogin = comment.getOwner().getLogin();
|
||||
}
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public String getText() {return text;}
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
public String getAuthor() {return authorLogin;}
|
||||
}
|
41
src/main/java/com/webproglabs/lab1/dto/PostDto.java
Normal file
41
src/main/java/com/webproglabs/lab1/dto/PostDto.java
Normal file
@ -0,0 +1,41 @@
|
||||
package com.webproglabs.lab1.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PostDto {
|
||||
private Long id;
|
||||
@NotBlank
|
||||
private String text;
|
||||
@NotNull
|
||||
private List<CommentDto> comments = new ArrayList<>();
|
||||
@NotBlank
|
||||
private String authorLogin;
|
||||
|
||||
public PostDto(Post post){
|
||||
this.id = post.getId();
|
||||
this.text = post.getText();
|
||||
for(Comment comment: post.getComments()){
|
||||
comments.add(new CommentDto(comment));
|
||||
}
|
||||
this.authorLogin = post.getAuthor().getLogin();
|
||||
}
|
||||
public PostDto(){}
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public String getText() {return text;}
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
public List<CommentDto> getComments() {return comments;}
|
||||
public String getAuthor() {return authorLogin;}
|
||||
}
|
54
src/main/java/com/webproglabs/lab1/dto/TopicDto.java
Normal file
54
src/main/java/com/webproglabs/lab1/dto/TopicDto.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.webproglabs.lab1.dto;
|
||||
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.Topic;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TopicDto {
|
||||
private Long id;
|
||||
@NotBlank
|
||||
private String name;
|
||||
@NotBlank
|
||||
private String description;
|
||||
@NotNull
|
||||
private List<PostDto> posts = new ArrayList<>();
|
||||
|
||||
public TopicDto(Topic topic) {
|
||||
this.id = topic.getId();
|
||||
this.name = topic.getName();
|
||||
this.description = topic.getDescription();
|
||||
for(Post post: topic.getPosts()){
|
||||
posts.add(new PostDto(post));
|
||||
}
|
||||
}
|
||||
public TopicDto(){}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<PostDto> getPosts() {
|
||||
return posts;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
55
src/main/java/com/webproglabs/lab1/dto/UserDto.java
Normal file
55
src/main/java/com/webproglabs/lab1/dto/UserDto.java
Normal file
@ -0,0 +1,55 @@
|
||||
package com.webproglabs.lab1.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import com.webproglabs.lab1.models.UserRole;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class UserDto {
|
||||
private Long id;
|
||||
@NotBlank
|
||||
private String login;
|
||||
@NotBlank
|
||||
private String password;
|
||||
@NotNull
|
||||
private List<CommentDto> comments = new ArrayList<>();
|
||||
@NotNull
|
||||
private List<PostDto> posts = new ArrayList<>();
|
||||
@NotNull
|
||||
private UserRole role;
|
||||
|
||||
|
||||
public UserDto(){}
|
||||
|
||||
public UserDto(User user){
|
||||
this.id = user.getId();
|
||||
this.login = user.getLogin();
|
||||
this.password = user.getPassword();
|
||||
this.role = user.getRole();
|
||||
for(Comment comment: user.getComments()){
|
||||
comments.add(new CommentDto(comment));
|
||||
}
|
||||
for (Post post: user.getPosts()) {
|
||||
posts.add(new PostDto(post));
|
||||
}
|
||||
}
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public String getLogin() {return login;}
|
||||
public void setLogin(String login) {this.login = login;}
|
||||
public String getPassword() {return password;}
|
||||
public UserRole getRole() {return role;}
|
||||
public void setPassword(String password) {this.password = password;}
|
||||
|
||||
public List<CommentDto> getComments() {return comments;}
|
||||
public List<PostDto> getPosts() {return posts;}
|
||||
}
|
40
src/main/java/com/webproglabs/lab1/dto/UserSignupDto.java
Normal file
40
src/main/java/com/webproglabs/lab1/dto/UserSignupDto.java
Normal file
@ -0,0 +1,40 @@
|
||||
package com.webproglabs.lab1.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
public class UserSignupDto {
|
||||
@NotBlank
|
||||
@Size(min = 4, max = 64)
|
||||
private String login;
|
||||
@NotBlank
|
||||
@Size(min = 4, max = 64)
|
||||
private String password;
|
||||
@NotBlank
|
||||
@Size(min = 4, max = 64)
|
||||
private String passwordConfirm;
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getPasswordConfirm() {
|
||||
return passwordConfirm;
|
||||
}
|
||||
|
||||
public void setPasswordConfirm(String passwordConfirm) {
|
||||
this.passwordConfirm = passwordConfirm;
|
||||
}
|
||||
}
|
82
src/main/java/com/webproglabs/lab1/models/Comment.java
Normal file
82
src/main/java/com/webproglabs/lab1/models/Comment.java
Normal file
@ -0,0 +1,82 @@
|
||||
package com.webproglabs.lab1.models;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
public class Comment {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String text;
|
||||
|
||||
@ManyToOne()
|
||||
private User owner;
|
||||
|
||||
@ManyToOne()
|
||||
private Post post;
|
||||
|
||||
public Comment(){};
|
||||
public Comment(String text, User owner, Post post) {
|
||||
this.text = text;
|
||||
this.owner = owner;
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public User getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(User owner) {
|
||||
this.owner.getComments().remove(this);
|
||||
this.owner = owner;
|
||||
if (!owner.getComments().contains(this)) {
|
||||
owner.getComments().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Post getPost() {return post; }
|
||||
|
||||
public void setPost(Post post) {
|
||||
this.post.getComments().remove(this);
|
||||
this.post = post;
|
||||
if (!post.getComments().contains(this)) {
|
||||
post.getComments().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Comment comment = (Comment) o;
|
||||
return Objects.equals(id, comment.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
public String ToString() {
|
||||
return "Comment{" +
|
||||
"id=" + id +
|
||||
", text='" + text + '\'' +
|
||||
", owner='" + owner.ToString() + '\'' +
|
||||
", post='" + post.ToString() + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
97
src/main/java/com/webproglabs/lab1/models/Post.java
Normal file
97
src/main/java/com/webproglabs/lab1/models/Post.java
Normal file
@ -0,0 +1,97 @@
|
||||
package com.webproglabs.lab1.models;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
public class Post {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String text;
|
||||
|
||||
@OneToMany(mappedBy = "post", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<Comment> comments = new ArrayList<Comment>();
|
||||
|
||||
@ManyToOne()
|
||||
private User author;
|
||||
|
||||
@ManyToOne()
|
||||
private Topic topic;
|
||||
|
||||
public Post(){}
|
||||
public Post(String text, User author, Topic topic) {
|
||||
this.text = text;
|
||||
this.author = author;
|
||||
this.topic = topic;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public User getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(User author) {
|
||||
this.author.getPosts().remove(this);
|
||||
this.author = author;
|
||||
if (!author.getPosts().contains(this)) {
|
||||
author.getPosts().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public Topic getTopic() {
|
||||
return topic;
|
||||
}
|
||||
|
||||
public void setTopic(Topic topic) {
|
||||
this.topic.getPosts().remove(this);
|
||||
this.topic = topic;
|
||||
if (!topic.getPosts().contains(this)) {
|
||||
topic.getPosts().add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Comment> getComments() { return comments; }
|
||||
|
||||
public void addComment(Comment comment) {
|
||||
this.comments.add(comment);
|
||||
if (comment.getPost() != this) {
|
||||
comment.setPost(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Post post = (Post) o;
|
||||
return Objects.equals(id, post.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
public String ToString() {
|
||||
return "Post{" +
|
||||
"id=" + id +
|
||||
", text='" + text + '\'' +
|
||||
", author='" + author.ToString() + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
78
src/main/java/com/webproglabs/lab1/models/Topic.java
Normal file
78
src/main/java/com/webproglabs/lab1/models/Topic.java
Normal file
@ -0,0 +1,78 @@
|
||||
package com.webproglabs.lab1.models;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
public class Topic {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
@OneToMany(mappedBy = "topic", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<Post> posts;
|
||||
|
||||
public Topic(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.posts = new ArrayList<Post>();
|
||||
}
|
||||
public Topic(){}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public List<Post> getPosts() {
|
||||
return posts;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void addPost(Post post) {
|
||||
this.posts.add(post);
|
||||
if (post.getTopic() != this) {
|
||||
post.setTopic(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Topic topic = (Topic) o;
|
||||
return Objects.equals(id, topic.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
public String ToString() {
|
||||
return "Topic{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
110
src/main/java/com/webproglabs/lab1/models/User.java
Normal file
110
src/main/java/com/webproglabs/lab1/models/User.java
Normal file
@ -0,0 +1,110 @@
|
||||
package com.webproglabs.lab1.models;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Entity
|
||||
@Table(name="users")
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 64)
|
||||
@NotBlank
|
||||
@Size(min = 3, max = 64)
|
||||
private String login;
|
||||
|
||||
@Column(nullable = false, length = 64)
|
||||
@NotBlank
|
||||
@Size(min = 4, max = 64)
|
||||
private String password;
|
||||
|
||||
private UserRole role;
|
||||
|
||||
@OneToMany(mappedBy = "owner", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<Comment> comments = new ArrayList<Comment>();
|
||||
|
||||
@OneToMany(mappedBy = "author", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<Post> posts = new ArrayList<Post>();
|
||||
|
||||
public User(){}
|
||||
public User(String login, String password) {
|
||||
this.login = login;
|
||||
this.password=password;
|
||||
this.role = UserRole.USER;
|
||||
};
|
||||
|
||||
public User(String login, String password, UserRole role) {
|
||||
this.login = login;
|
||||
this.password=password;
|
||||
this.role = role;
|
||||
};
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public UserRole getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public List<Comment> getComments() { return comments; }
|
||||
|
||||
public List<Post> getPosts() {return posts; }
|
||||
|
||||
public void addComment(Comment comment) {
|
||||
this.comments.add(comment);
|
||||
if (comment.getOwner() != this) {
|
||||
comment.setOwner(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void addPost(Post post) {
|
||||
this.posts.add(post);
|
||||
if (post.getAuthor() != this) {
|
||||
post.setAuthor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
public String ToString() {
|
||||
return "User{" +
|
||||
"id=" + id +
|
||||
", login='" + login + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
20
src/main/java/com/webproglabs/lab1/models/UserRole.java
Normal file
20
src/main/java/com/webproglabs/lab1/models/UserRole.java
Normal file
@ -0,0 +1,20 @@
|
||||
package com.webproglabs.lab1.models;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public enum UserRole implements GrantedAuthority {
|
||||
ADMIN,
|
||||
USER;
|
||||
|
||||
private static final String PREFIX = "ROLE_";
|
||||
|
||||
@Override
|
||||
public String getAuthority() {
|
||||
return PREFIX + this.name();
|
||||
}
|
||||
|
||||
public static final class AsString {
|
||||
public static final String ADMIN = PREFIX + "ADMIN";
|
||||
public static final String USER = PREFIX + "USER";
|
||||
}
|
||||
}
|
142
src/main/java/com/webproglabs/lab1/mvc/FeedMvcController.java
Normal file
142
src/main/java/com/webproglabs/lab1/mvc/FeedMvcController.java
Normal file
@ -0,0 +1,142 @@
|
||||
package com.webproglabs.lab1.mvc;
|
||||
|
||||
import com.webproglabs.lab1.dto.CommentDto;
|
||||
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();
|
||||
}
|
||||
|
||||
@GetMapping(value = {"commentModal/{topicId}/{postId}"})
|
||||
public String getCommentModal(@PathVariable Long topicId,@PathVariable Long postId, Model model) {
|
||||
model.addAttribute("selectedPost", new PostDto(postService.findPostById(postId)));
|
||||
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 "commentModal";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"comment/{authorId}/{topicId}/{postId}/"})
|
||||
public String createComment(@PathVariable Long authorId, @PathVariable Long topicId, @PathVariable Long postId, @RequestParam(value="commentInputField") String commentInputField) {
|
||||
commentService.addComment(commentInputField, authorId, postId);
|
||||
return "redirect:/feed/" + topicId.toString();
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/deleteComment/{id}/{topicId}"})
|
||||
public String deleteComment(@PathVariable Long id, @PathVariable Long topicId) {
|
||||
commentService.deleteComment(id);
|
||||
return "redirect:/feed/" + topicId.toString();
|
||||
}
|
||||
|
||||
@GetMapping(value = {"commentEditModal/{id}/{topicId}"})
|
||||
public String getCommentEditModal(@PathVariable Long id,@PathVariable Long topicId, Model model) {
|
||||
model.addAttribute("selectedComment", new CommentDto(commentService.findCommentById(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 "editCommentModal";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"editComment/{topicId}/{commentId}/"})
|
||||
public String editComment(@PathVariable Long topicId,@PathVariable Long commentId, @RequestParam(value="commentEditField") String commentEditField) {
|
||||
commentService.updateComment(commentId, commentEditField);
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package com.webproglabs.lab1.mvc;
|
||||
|
||||
import com.webproglabs.lab1.dto.UserDto;
|
||||
import com.webproglabs.lab1.dto.UserSignupDto;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import com.webproglabs.lab1.models.UserRole;
|
||||
import com.webproglabs.lab1.services.UserService;
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
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.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/users")
|
||||
public class UserMvcController {
|
||||
private final UserService userService;
|
||||
|
||||
public UserMvcController(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String getUsersPage(Model model){
|
||||
model.addAttribute("profiles", userService.findAllUsers().stream().map(UserDto::new).toList());
|
||||
return "users";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/{id}"})
|
||||
@Secured({UserRole.AsString.ADMIN})
|
||||
public String deleteUser(@PathVariable Long id) {
|
||||
userService.deleteUser(id);
|
||||
return "redirect:/users";
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/{login}"})
|
||||
public String getUserPage(@PathVariable String login, Model model) {
|
||||
model.addAttribute("user", new UserDto(userService.findUserByLogin(login)));
|
||||
return "userPage";
|
||||
}
|
||||
|
||||
@GetMapping(value = {"/settings"})
|
||||
public String getUserEditPage(Model model) {
|
||||
UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var currentUser = userService.findUserByLogin(principal.getUsername());
|
||||
model.addAttribute("user", new UserDto(userService.findUserById(currentUser.getId())));
|
||||
model.addAttribute("userDto", new UserSignupDto());
|
||||
|
||||
return "userEditPage";
|
||||
}
|
||||
|
||||
@PostMapping(value = {"/edit/{id}"})
|
||||
public String editUserData(@PathVariable Long id, @ModelAttribute("userDto") @Valid UserSignupDto userSignupDto,
|
||||
BindingResult bindingResult,
|
||||
Model model) {
|
||||
UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var currentUser = userService.findUserByLogin(principal.getUsername());
|
||||
model.addAttribute("user", new UserDto(userService.findUserById(currentUser.getId())));
|
||||
model.addAttribute("userDto", new UserSignupDto());
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||
return "userEditPage";
|
||||
}
|
||||
try {
|
||||
final User user = userService.updateUser(id, userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
|
||||
model.addAttribute("success", "Данные успешно изменены");
|
||||
return "userEditPage";
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("errors", e.getMessage());
|
||||
return "userEditPage";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.webproglabs.lab1.mvc;
|
||||
|
||||
import com.webproglabs.lab1.dto.UserSignupDto;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import com.webproglabs.lab1.services.UserService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@Controller
|
||||
@RequestMapping()
|
||||
public class UserSignupMvcController {
|
||||
public static final String SIGNUP_URL = "/signup";
|
||||
|
||||
private final UserService userService;
|
||||
|
||||
public UserSignupMvcController(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String toFeed() {
|
||||
return "redirect:/feed";
|
||||
}
|
||||
|
||||
@GetMapping(SIGNUP_URL)
|
||||
public String showSignupForm(Model model) {
|
||||
model.addAttribute("userDto", new UserSignupDto());
|
||||
return "signup";
|
||||
}
|
||||
|
||||
@PostMapping(SIGNUP_URL)
|
||||
public String signup(@ModelAttribute("userDto") @Valid UserSignupDto userSignupDto,
|
||||
BindingResult bindingResult,
|
||||
Model model) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||
return "signup";
|
||||
}
|
||||
try {
|
||||
final User user = userService.createUser(userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
|
||||
return "redirect:/login?created=" + user.getLogin();
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("errors", e.getMessage());
|
||||
return "signup";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.webproglabs.lab1.services;
|
||||
|
||||
import com.webproglabs.lab1.dao.CommentRepository;
|
||||
import com.webproglabs.lab1.dao.PostRepository;
|
||||
import com.webproglabs.lab1.dao.UserRepository;
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class CommentService {
|
||||
private final UserRepository userRepository;
|
||||
private final CommentRepository commentRepository;
|
||||
private final PostRepository postRepository;
|
||||
|
||||
public CommentService(UserRepository profileRepository, CommentRepository commentRepository, PostRepository postRepository) {
|
||||
this.userRepository = profileRepository;
|
||||
this.commentRepository = commentRepository;
|
||||
this.postRepository = postRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Comment findCommentById(Long id) {
|
||||
final Optional<Comment> comment = commentRepository.findById(id);
|
||||
return comment.orElseThrow(EntityNotFoundException::new);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Comment> findAllComments() {
|
||||
return commentRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Comment addComment(String text, Long userId, Long postId) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
throw new IllegalArgumentException("Comment data is null or empty");
|
||||
}
|
||||
try{
|
||||
User user = userRepository.findById(userId).get();
|
||||
Post post = postRepository.findById(postId).get();
|
||||
Comment comment = new Comment(text, user, post);
|
||||
user.addComment(comment);
|
||||
post.addComment(comment);
|
||||
userRepository.save(user);
|
||||
postRepository.save(post);
|
||||
return commentRepository.save(comment);
|
||||
}
|
||||
catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Comment updateComment(Long id, String text) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
throw new IllegalArgumentException("Comment data is null or empty");
|
||||
}
|
||||
Comment currentComment = findCommentById(id);
|
||||
currentComment.setText(text);
|
||||
final User owner = currentComment.getOwner();
|
||||
userRepository.save(owner);
|
||||
final Post post = currentComment.getPost();
|
||||
postRepository.save(post);
|
||||
return commentRepository.save(currentComment);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Comment deleteComment(Long id) {
|
||||
final Comment currentComment = findCommentById(id);
|
||||
commentRepository.delete(currentComment);
|
||||
return currentComment;
|
||||
}
|
||||
}
|
86
src/main/java/com/webproglabs/lab1/services/PostService.java
Normal file
86
src/main/java/com/webproglabs/lab1/services/PostService.java
Normal file
@ -0,0 +1,86 @@
|
||||
package com.webproglabs.lab1.services;
|
||||
|
||||
import com.webproglabs.lab1.dao.CommentRepository;
|
||||
import com.webproglabs.lab1.dao.PostRepository;
|
||||
import com.webproglabs.lab1.dao.TopicRepository;
|
||||
import com.webproglabs.lab1.dao.UserRepository;
|
||||
import com.webproglabs.lab1.models.Comment;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.Topic;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class PostService {
|
||||
private final PostRepository postRepository;
|
||||
private final CommentRepository commentRepository;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final TopicRepository topicRepository;
|
||||
|
||||
public PostService(PostRepository postRepository, CommentRepository commentRepository, UserRepository userRepository, TopicRepository topicRepository) {
|
||||
this.postRepository = postRepository;
|
||||
this.commentRepository = commentRepository;
|
||||
this.userRepository = userRepository;
|
||||
this.topicRepository = topicRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Post findPostById(Long id) {
|
||||
final Optional<Post> post = postRepository.findById(id);
|
||||
return post.orElseThrow(EntityNotFoundException::new);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Post> findAllPosts() {
|
||||
return postRepository.findAll();
|
||||
}
|
||||
|
||||
@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)) {
|
||||
throw new IllegalArgumentException("Post data is null or empty");
|
||||
}
|
||||
User author = userRepository.findById(authorId).get();
|
||||
Topic topic = topicRepository.findById(topicId).get();
|
||||
Post post = new Post(text, author, topic);
|
||||
author.addPost(post);
|
||||
topic.addPost(post);
|
||||
userRepository.save(author);
|
||||
topicRepository.save(topic);
|
||||
return postRepository.save(post);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Post updatePost(Long id, String text) {
|
||||
if (!StringUtils.hasText(text)) {
|
||||
throw new IllegalArgumentException("Post data is null or empty");
|
||||
}
|
||||
final Post currentPost = findPostById(id);
|
||||
currentPost.setText(text);
|
||||
final User author = currentPost.getAuthor();
|
||||
userRepository.save(author);
|
||||
final Topic topic = currentPost.getTopic();
|
||||
topicRepository.save(topic);
|
||||
return postRepository.save(currentPost);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Post deletePost(Long id) {
|
||||
final Post currentPost = findPostById(id);
|
||||
postRepository.delete(currentPost);
|
||||
return currentPost;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.webproglabs.lab1.services;
|
||||
|
||||
import com.webproglabs.lab1.dao.TopicRepository;
|
||||
import com.webproglabs.lab1.models.Post;
|
||||
import com.webproglabs.lab1.models.Topic;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class TopicService {
|
||||
private final TopicRepository topicRepository;
|
||||
|
||||
public TopicService(TopicRepository topicRepository) {
|
||||
this.topicRepository = topicRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Topic addTopic(String name, String description) {
|
||||
if (!StringUtils.hasText(name) || !StringUtils.hasText(description)) {
|
||||
throw new IllegalArgumentException("Name is null or empty");
|
||||
}
|
||||
final Topic topic = new Topic(name, description);
|
||||
return topicRepository.save(topic);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Topic findTopicById(Long id) {
|
||||
final Topic topic = topicRepository.findById(id).orElse(null);
|
||||
if (topic == null) {
|
||||
throw new EntityNotFoundException(String.format(" topic with id [%s] is not found", id));
|
||||
}
|
||||
return topic;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Topic> findAllTopics() {
|
||||
return topicRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Topic updateTopic(Long id, String name, String description) {
|
||||
if (!StringUtils.hasText(name) || !StringUtils.hasText(description)) {
|
||||
throw new IllegalArgumentException("Name is null or empty");
|
||||
}
|
||||
final Topic topic = findTopicById(id);
|
||||
topic.setName(name);
|
||||
topic.setDescription(description);
|
||||
return topicRepository.save(topic);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Topic deleteTopic(Long id) {
|
||||
final Topic topic = findTopicById(id);
|
||||
topicRepository.delete(topic);
|
||||
return topic;
|
||||
}
|
||||
|
||||
}
|
102
src/main/java/com/webproglabs/lab1/services/UserService.java
Normal file
102
src/main/java/com/webproglabs/lab1/services/UserService.java
Normal file
@ -0,0 +1,102 @@
|
||||
package com.webproglabs.lab1.services;
|
||||
|
||||
import com.webproglabs.lab1.dao.UserRepository;
|
||||
import com.webproglabs.lab1.models.User;
|
||||
import com.webproglabs.lab1.models.UserRole;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
import javax.transaction.Transactional;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class UserService implements UserDetailsService {
|
||||
private final UserRepository userRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
|
||||
this.userRepository = userRepository;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User findUserById(Long id) {
|
||||
final Optional<User> user = userRepository.findById(id);
|
||||
return user.orElseThrow(EntityNotFoundException::new);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User findUserByLogin(String login) {
|
||||
final User user = userRepository.findOneByLoginIgnoreCase(login).orElse(null);
|
||||
return user;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<User> findAllUsers() {
|
||||
return userRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User createUser(String login, String password, String passwordConfirm, UserRole role) {
|
||||
if (findUserByLogin(login) != null) {
|
||||
throw new IllegalArgumentException("User " + login + " already exists");
|
||||
}
|
||||
final User user = new User(login, passwordEncoder.encode(password), role);
|
||||
if (!Objects.equals(password, passwordConfirm)) {
|
||||
throw new IllegalArgumentException("Passwords not equals");
|
||||
}
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User createUser(String login, String password, String passwordConfirm) {
|
||||
return createUser(login, password, passwordConfirm, UserRole.USER);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User updateUser(Long id, String login, String password, String passwordConfirm) {
|
||||
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
|
||||
throw new IllegalArgumentException("User data is null or empty");
|
||||
}
|
||||
|
||||
final User currentUser = findUserById(id);
|
||||
|
||||
if (Objects.equals(password, currentUser.getPassword())) {
|
||||
throw new IllegalArgumentException("New password is the same as old");
|
||||
}
|
||||
|
||||
if (!Objects.equals(password, passwordConfirm)) {
|
||||
throw new IllegalArgumentException("Password mismatch");
|
||||
}
|
||||
|
||||
currentUser.setLogin(login);
|
||||
currentUser.setPassword(passwordEncoder.encode(password));
|
||||
return userRepository.save(currentUser);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public User deleteUser(Long id) {
|
||||
final User currentUser = findUserById(id);
|
||||
userRepository.delete(currentUser);
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
final User userEntity = findUserByLogin(username);
|
||||
if (userEntity == null) {
|
||||
throw new UsernameNotFoundException(username);
|
||||
}
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole()));
|
||||
}
|
||||
}
|
32
src/main/resources/templates/commentModal.html
Normal file
32
src/main/resources/templates/commentModal.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="commentCreate" tabindex="-1" role="dialog" aria-labelledby="commentCreateLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="commentCreateLabel">Создать комментарий</h5>
|
||||
</div>
|
||||
<form th:action="@{/feed/comment/{id}/{topicId}/{postId}/{text} (id=${selectedProfile.id}, topicId=${selectedTopic.id}, postId=${selectedPost.id}, text=${commentInputField}) }" method="post" class="modal-body text-center">
|
||||
<p>Текст комментария:</p>
|
||||
<input th:value="${commentInputField}" id="commentInputField" name="commentInputField" 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>
|
49
src/main/resources/templates/default.html
Normal file
49
src/main/resources/templates/default.html
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>СоцСеточка</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
|
||||
<link rel="stylesheet" href="/webjars/bootstrap/5.1.3/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="/webjars/font-awesome/6.1.0/css/all.min.css"/>
|
||||
<link rel="stylesheet" href="/css/style.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="bg-light w-75 rounded-pill text-center pt-4 pb-4 mt-3 mx-auto">
|
||||
<p class='text-center h3'> СоцСеточка</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class='h4 mt-2 text-center'>
|
||||
<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="/users/settings" 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>
|
||||
</div>
|
||||
|
||||
<div >
|
||||
<div layout:fragment="content"></div>
|
||||
</div>
|
||||
</body>
|
||||
<script type="text/javascript">
|
||||
window.onload = () => {
|
||||
$('#postEdit').modal('show');
|
||||
$('#commentCreate').modal('show');
|
||||
$('#commentEdit').modal('show');
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
30
src/main/resources/templates/editCommentModal.html
Normal file
30
src/main/resources/templates/editCommentModal.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!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="commentEdit" tabindex="-1" role="dialog" aria-labelledby="commentEditLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="commentEditLabel">Редактировать комментарий</h5>
|
||||
</div>
|
||||
<form th:action="@{/feed/editComment/{id}/{commentId}/{text} (id=${selectedTopic.id}, commentId=${selectedComment.id}, text=${commentEditField}) }" method="post" class="modal-body text-center">
|
||||
<p>Новый текст комментария:</p>
|
||||
<input th:attr="value = ${selectedComment.text}" id="commentEditField" name="commentEditField" 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/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>
|
13
src/main/resources/templates/error.html
Normal file
13
src/main/resources/templates/error.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{default}">
|
||||
<body>
|
||||
<div class="container" layout:fragment="content">
|
||||
<div class="alert alert-danger">
|
||||
<span th:text="${error}"></span>
|
||||
</div>
|
||||
<a href="/">На главную</a>
|
||||
</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 mb-3 w-100" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Выбор темы
|
||||
</button>
|
||||
<ul class="dropdown-menu w-100" >
|
||||
<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>
|
110
src/main/resources/templates/feedPosts.html
Normal file
110
src/main/resources/templates/feedPosts.html
Normal file
@ -0,0 +1,110 @@
|
||||
<!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='mb-3 mx-auto w-75'>
|
||||
<div class="text-center w-100 border border-2 bg-light">
|
||||
<p class="text-center h3" th:text="${selectedTopic.name}"></p>
|
||||
<p class="text-center fw-light" th:text="${selectedTopic.description}"></p>
|
||||
</div>
|
||||
<p class="text-end h3 " 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="@{/users/{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}/{topicId} (id=${comment.id}, topicId=${selectedTopic.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}/{topicId} (id=${comment.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>
|
||||
</div>
|
||||
<form th:action="@{/feed/commentModal/{topicId}/{postId}/ ( topicId=${selectedTopic.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>
|
31
src/main/resources/templates/login.html
Normal file
31
src/main/resources/templates/login.html
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{default}">
|
||||
<body>
|
||||
<div class="container" layout:fragment="content">
|
||||
<div th:if="${param.error}" class="alert alert-danger margin-bottom">
|
||||
Пользователь не найден или пароль указан не верно
|
||||
</div>
|
||||
<div th:if="${param.logout}" class="alert alert-success margin-bottom">
|
||||
Выход успешно произведен
|
||||
</div>
|
||||
<div th:if="${param.created}" class="alert alert-success margin-bottom">
|
||||
Пользователь '<span th:text="${param.created}"></span>' успешно создан
|
||||
</div>
|
||||
<form th:action="@{/login}" method="post" class="container-padding">
|
||||
<div class="mb-3">
|
||||
<input type="text" name="username" id="username" class="form-control"
|
||||
placeholder="Логин" required="true" autofocus="true"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input type="password" name="password" id="password" class="form-control"
|
||||
placeholder="Пароль" required="true"/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success button-fixed">Войти</button>
|
||||
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
28
src/main/resources/templates/signup.html
Normal file
28
src/main/resources/templates/signup.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!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">
|
||||
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
|
||||
<form action="#" th:action="@{/signup}" th:object="${userDto}" method="post">
|
||||
<div class="mb-3">
|
||||
<input type="text" class="form-control" th:field="${userDto.login}"
|
||||
placeholder="Логин" required="true" autofocus="true" maxlength="64"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input type="password" class="form-control" th:field="${userDto.password}"
|
||||
placeholder="Пароль" required="true" minlength="4" maxlength="64"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input type="password" class="form-control" th:field="${userDto.passwordConfirm}"
|
||||
placeholder="Пароль (подтверждение)" required="true" minlength="4" maxlength="64"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-success button-fixed">Создать</button>
|
||||
<a class="btn btn-primary button-fixed" href="/login">Назад</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
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>
|
31
src/main/resources/templates/userEditPage.html
Normal file
31
src/main/resources/templates/userEditPage.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!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 th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
|
||||
<div th:if="${success}" th:text="${success}" class="margin-bottom text-success"></div>
|
||||
<div class="text-start mx-auto w-50 border p-5">
|
||||
<p class='h5'>Изменение данных пользователя</p>
|
||||
<p th:text="${'Логин: ' + user.login}"></p>
|
||||
|
||||
<form action="#" th:action="@{/users/edit/{id} (id=${user.id})}" th:object="${userDto}" method="post">
|
||||
<p>Новый логин:</p>
|
||||
<input th:field="${userDto.login}" type="text" class="mb-2 form-control" required="true" autofocus="true" maxlength="64"/>
|
||||
<p>Новый пароль:</p>
|
||||
<input th:field="${userDto.password}" type="password" class="mb-2 form-control" required="true" minlength="4" maxlength="64"/>
|
||||
<p>Повторите пароль:</p>
|
||||
<input th:field="${userDto.passwordConfirm}" type="password" class="mb-2 form-control" required="true" minlength="4" maxlength="64"/>
|
||||
<button type="submit" class="btn btn-success" >Сохранить изменения</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
29
src/main/resources/templates/userPage.html
Normal file
29
src/main/resources/templates/userPage.html
Normal file
@ -0,0 +1,29 @@
|
||||
<!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="text-start mx-auto w-50 border p-5">
|
||||
<p class='h5'>Профиль</p>
|
||||
<p th:text="${'Логин: ' + user.login}"></p>
|
||||
<p class='h6 '>Список постов пользователя: </p>
|
||||
|
||||
<div th:if="${user.posts.size()>0}">
|
||||
<div th:each="post: ${user.posts}">
|
||||
<p th:text="${post.text}" class="mb-3 ms-2 border p-2"></p>
|
||||
</div>
|
||||
</div>
|
||||
<p th:unless="${user.posts.size()>0}">
|
||||
Нет постов
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
36
src/main/resources/templates/users.html
Normal file
36
src/main/resources/templates/users.html
Normal file
@ -0,0 +1,36 @@
|
||||
<!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">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content" class="text-center">
|
||||
|
||||
<div th:each="profile: ${profiles}" class="mb-2">
|
||||
<div class="text-center">
|
||||
<div class="text-start mx-auto w-50 border shadow p-3">
|
||||
<p class='h5'>Профиль</p>
|
||||
<p th:text="${'Логин: ' + profile.login}"></p>
|
||||
<p class='h6 '>Список постов пользователя: </p>
|
||||
|
||||
<div th:if="${profile.posts.size()>0}">
|
||||
<div th:each="post: ${profile.posts}">
|
||||
<p th:text="${post.text}" class="mb-3 ms-2 border p-2"></p>
|
||||
</div>
|
||||
</div>
|
||||
<p th:unless="${profile.posts.size()>0}">
|
||||
Нет постов
|
||||
</p>
|
||||
<div class="text-end" th:if="${profile.login!='admin'}">
|
||||
<form action="#" th:action="@{/users/{id} (id=${profile.id})}" method="post" >
|
||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user