Compare commits

..

No commits in common. "048a00a4a43b35bee06754f3cb2457500af03c2c" and "aefeeeee487bf3c0c9885cebfce3e3ca7ec0fc9f" have entirely different histories.

69 changed files with 6049 additions and 1135 deletions

Binary file not shown.

3828
data.trace.db Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,10 @@
package com.webproglabs.lab1; package com.webproglabs.lab1;
import com.webproglabs.lab1.lab34.model.enums.UserRole; import com.webproglabs.lab1.lab34.controller.ProfileController;
import com.webproglabs.lab1.lab34.mvc.UserSignUpMvcController; import com.webproglabs.lab1.lab34.controller.mvc_controllers.UserSignupMvcController;
import com.webproglabs.lab1.lab34.services.UserService; import com.webproglabs.lab1.lab34.jwt.JwtFilter;
import com.webproglabs.lab1.lab34.model.UserRole;
import com.webproglabs.lab1.lab34.services.ProfileService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -15,10 +17,12 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint; import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
@ -32,16 +36,18 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class); private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private static final String LOGIN_URL = "/login"; private static final String LOGIN_URL = "/login";
public static final String SPA_URL_MASK = "/{path:[^\\.]*}"; public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
private final UserService userService; private final ProfileService userService;
private final JwtFilter jwtFilter;
public SecurityConfiguration(UserService userService) { public SecurityConfiguration(ProfileService userService) {
this.userService = userService; this.userService = userService;
this.jwtFilter = new JwtFilter(userService);
createAdminOnStartup(); createAdminOnStartup();
} }
private void createAdminOnStartup() { private void createAdminOnStartup() {
final String admin = "admin"; final String admin = "admin";
if (userService.findUserByLogin(admin) == null) { if (userService.findByLogin(admin) == null) {
log.info("Admin user successfully created"); log.info("Admin user successfully created");
try { try {
userService.createUser(admin, admin, admin, UserRole.ADMIN); userService.createUser(admin, admin, admin, UserRole.ADMIN);
@ -53,12 +59,13 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint()); http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
http.headers().frameOptions().sameOrigin().and() http.headers().frameOptions().sameOrigin().and()
.cors().and() .cors().and()
.csrf().disable() .csrf().disable()
.authorizeRequests() .authorizeRequests()
.antMatchers(UserSignUpMvcController.SIGNUP_URL).permitAll() .antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll()
.antMatchers(HttpMethod.GET, LOGIN_URL).permitAll() .antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
.and() .and()

View File

@ -0,0 +1,105 @@
package com.webproglabs.lab1;
import com.webproglabs.lab1.lab34.controller.ProfileController;
import com.webproglabs.lab1.lab34.controller.mvc_controllers.UserSignupMvcController;
import com.webproglabs.lab1.lab34.jwt.JwtFilter;
import com.webproglabs.lab1.lab34.model.UserRole;
import com.webproglabs.lab1.lab34.services.ProfileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.util.LinkedHashMap;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
@Profile("spa")
public class SecurityConfigurationSPA 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;
private final JwtFilter jwtFilter;
public SecurityConfigurationSPA(ProfileService userService) {
this.userService = userService;
this.jwtFilter = new JwtFilter(userService);
createAdminOnStartup();
}
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);
}
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
log.info("Creating security configuration");
http.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/", SPA_URL_MASK).permitAll()
.antMatchers(HttpMethod.POST, WebConfiguration.REST_API + "/profile" + ProfileController.URL_LOGIN).permitAll()
.anyRequest()
.authenticated()
.and()
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.anonymous();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/css/**")
.antMatchers("/js/**")
.antMatchers("/templates/**")
.antMatchers("/webjars/**")
.antMatchers("/swagger-resources/**")
.antMatchers("/v3/api-docs/**");
}
@Bean
public AuthenticationEntryPoint delegatingEntryPoint() {
final LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> map = new LinkedHashMap();
map.put(new AntPathRequestMatcher("/"), new LoginUrlAuthenticationEntryPoint("/login"));
map.put(new AntPathRequestMatcher("/api/1.0/**"), new Http403ForbiddenEntryPoint());
final DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(map);
entryPoint.setDefaultEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"));
return entryPoint;
}
}

View File

@ -1,5 +1,6 @@
package com.webproglabs.lab1; package com.webproglabs.lab1;
import com.webproglabs.lab1.lab34.OpenAPI30Configuration;
import org.springframework.boot.web.server.ErrorPage; import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
@ -12,7 +13,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class WebConfiguration implements WebMvcConfigurer { public class WebConfiguration implements WebMvcConfigurer {
public static final String REST_API = "/api"; public static final String REST_API = OpenAPI30Configuration.API_PREFIX;
@Override @Override
public void addViewControllers(ViewControllerRegistry registry) { public void addViewControllers(ViewControllerRegistry registry) {
WebMvcConfigurer.super.addViewControllers(registry); WebMvcConfigurer.super.addViewControllers(registry);

View File

@ -0,0 +1,44 @@
package com.webproglabs.lab1.lab1;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
@RestController
public class Lab1Controller {
@GetMapping("/ilove")
public String ilove(@RequestParam(value = "thing", defaultValue = "cookies") String thing) {
return String.format("I love %s!", thing);
}
@GetMapping("/ask")
public String question(@RequestParam(value = "question", defaultValue = "Задайте вопрос") String question) {
if (question.contains("Задайте вопрос")) return question;
String[] answers = new String[] {
"Не знаю",
"Да",
"Нет",
"Спросите у мамы"
};
Random random = new Random();
return answers[random.nextInt(4)];
}
@GetMapping("/touppercase")
public String tuupper(@RequestParam(value = "content", defaultValue = "Введите строку") String content) {
return content.toUpperCase();
}
@GetMapping("/date")
public String date () {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
return dtf.format(now);
}
}

View File

@ -0,0 +1,27 @@
package com.webproglabs.lab1.lab2.config;
import com.webproglabs.lab1.lab2.domain.Lab2Int;
import com.webproglabs.lab1.lab2.domain.Lab2String;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Lab2Config {
@Bean(value="int")
public Lab2Int createLab2Int() {
return new Lab2Int();
}
@Bean(value="String")
public Lab2String createLab2String() {
return new Lab2String();
}
}
//фронт на жсон сервер был когда то
//сделать на основе старых сущностей сущности в жпа
//делаем сущности, зависимость для жпа, сервис для круд операций,
//тесты
//фронт не нужно
//двунправленная связь один ко многим

View File

@ -0,0 +1,35 @@
package com.webproglabs.lab1.lab2.controllers;
import com.webproglabs.lab1.lab2.Lab2Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Lab2Controller {
private final Lab2Service lab2Service;
public Lab2Controller(Lab2Service lab2Service) {this.lab2Service = lab2Service;}
@GetMapping("/lab2/sum")
public Object sum(@RequestParam (value = "first", defaultValue = "hello") String first,
@RequestParam (value = "second", defaultValue = "world") String second,
@RequestParam (value = "type") String type) {
return lab2Service.sum(first, second, type);
}
@GetMapping("/lab2/makeitbigger")
public Object makeItBigger(@RequestParam (value = "small") String small, @RequestParam (value = "type") String type) {
return lab2Service.makeItBigger(small, type);
}
@GetMapping("/lab2/reverse")
public Object reverse(@RequestParam(value="value")String value, @RequestParam (value = "type") String type) {
return lab2Service.reverse(value, type);
}
@GetMapping("lab2/lenght")
public Object lenght(@RequestParam(value = "value") String value, @RequestParam (value = "type") String type) {
return lab2Service.lenght(value, type);
}
}

View File

@ -0,0 +1,47 @@
package com.webproglabs.lab1.lab2;
import com.webproglabs.lab1.lab2.domain.Lab2Interface;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
@Service
public class Lab2Service {
private final ApplicationContext applicationContext;
public Lab2Service(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public Object sum(Object first, Object second, String type) {
if (type.equals("int")) {
first = Integer.parseInt(first.toString());
second = Integer.parseInt(second.toString());
}
final Lab2Interface summator =(Lab2Interface)applicationContext.getBean(type);
return summator.sum(first, second);
}
public Object makeItBigger(Object small, String type) {
if (type.equals("int")) {
small = Integer.parseInt(small.toString());
}
final Lab2Interface biggernator = (Lab2Interface)applicationContext.getBean(type);
return biggernator.makeItBigger(small);
}
public Object reverse (Object value, String type) {
if (type.equals("int")) {
value = Integer.parseInt(value.toString());
}
final Lab2Interface reversenator = (Lab2Interface) applicationContext.getBean(type);
return reversenator.reverse(value);
}
public Object lenght (Object value, String type) {
if (type.equals("int")) {
value = Integer.parseInt(value.toString());
}
final Lab2Interface leghtgetter = (Lab2Interface) applicationContext.getBean(type);
return leghtgetter.lenght(value);
}
}

View File

@ -0,0 +1,58 @@
package com.webproglabs.lab1.lab2.domain;
public class Lab2Int implements Lab2Interface<Integer>{
// @Override
// public Object sum(Object first, Object second) {
// if (!(first instanceof Integer && second instanceof Integer)) {
// throw new IllegalArgumentException();
// }
// return (Integer)first + (Integer)second;
// }
//
// @Override
// public Object makeItBigger(Object small) {
// if (!(small instanceof Integer)) {
// throw new IllegalArgumentException();
// }
// return (Integer)small * (Integer)small;
// }
//
// @Override
// public Object reverse(Object value) {
// if (!(value instanceof Integer)) {
// throw new IllegalArgumentException();
// }
// return (Integer)value * (-1);
// }
//
// @Override
// public Object lenght(Object value) {
// if (!(value instanceof Integer)) {
// throw new IllegalArgumentException();
// }
// int newvalue = (Integer)value;
// if (newvalue < 0) newvalue = newvalue * (-1);
// return newvalue;
// }
@Override
public Integer sum(Integer first, Integer second) {
return first + second;
}
@Override
public Integer makeItBigger(Integer small) {
return small*small;
}
@Override
public Integer reverse(Integer value) {
return value*(-1);
}
@Override
public Integer lenght(Integer value) {
if (value < 0) return value *(-1);
else return value;
}
}

View File

@ -0,0 +1,11 @@
package com.webproglabs.lab1.lab2.domain;
public interface Lab2Interface<T> {
T sum(T first, T second);
T makeItBigger (T small);
T reverse (T value);
T lenght (T value);
}

View File

@ -0,0 +1,61 @@
package com.webproglabs.lab1.lab2.domain;
public class Lab2String implements Lab2Interface<String>{
// @Override
// public Object sum(Object first, Object second) {
// if (!(first instanceof String && second instanceof String)) {
// throw new IllegalArgumentException();
// }
// return ((String) first).concat((String)second);
// }
//
// @Override
// public Object makeItBigger(Object small) {
// if (!(small instanceof String)) {
// throw new IllegalArgumentException();
// }
// return ((String) small).toUpperCase();
// }
//
// @Override
// public Object reverse(Object value) {
// if (!(value instanceof String)) {
// throw new IllegalArgumentException();
// }
// StringBuilder sb = new StringBuilder((String)value);
// sb.reverse();
// return sb.toString();
// }
//
// @Override
// public Object lenght(Object value) {
// if (!(value instanceof String)) {
// throw new IllegalArgumentException();
// }
// return ((String) value).length();
// }
@Override
public String sum(String first, String second) {
return first.concat(second);
}
@Override
public String makeItBigger(String small) {
return small.toUpperCase();
}
@Override
public String reverse(String value) {
StringBuilder sb = new StringBuilder(value);
sb.reverse();
return sb.toString();
}
@Override
public String lenght(String value) {
int len = value.length();
return Integer.toString(len);
}
}

View File

@ -0,0 +1,28 @@
package com.webproglabs.lab1.lab34;
import com.webproglabs.lab1.lab34.jwt.JwtFilter;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenAPI30Configuration {
public static final String API_PREFIX = "/api/1.0";
@Bean
public OpenAPI customizeOpenAPI() {
final String securitySchemeName = JwtFilter.TOKEN_BEGIN_STR;
return new OpenAPI()
.addSecurityItem(new SecurityRequirement()
.addList(securitySchemeName))
.components(new Components()
.addSecuritySchemes(securitySchemeName, new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")));
}
}

View File

@ -0,0 +1,59 @@
package com.webproglabs.lab1.lab34.controller;
import com.webproglabs.lab1.WebConfiguration;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.services.CommentService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/comment")
public class CommentController {
private final CommentService commentService;
public CommentController(CommentService commentService) {
this.commentService = commentService;
}
@GetMapping("/{id}")
public CommentDto getComment(@PathVariable Long id) {
return new CommentDto(commentService.findComment(id));
}
@GetMapping
public List<CommentDto> getComments() {
return commentService.findAllComments().stream()
.map(CommentDto::new)
.toList();
}
@GetMapping("/find")
public List<PostDto> getFilteredComments(@RequestParam("text") String text) {
return commentService.findFilteredComments(text).stream()
.map(PostDto::new)
.toList();
}
@PostMapping
public CommentDto createComment(@RequestParam("text") String text, @RequestParam("ownerId") Long id, @RequestParam("postId") Long postId){
final Comment comment = commentService.addComment(text, id, postId);
return new CommentDto(comment);
}
@PutMapping("/{id}")
public CommentDto updateComment(@RequestParam("text") String text, @PathVariable Long id) {
return new CommentDto(commentService.updateComment(id, text));
}
@DeleteMapping("/{id}")
public CommentDto deleteComment(@PathVariable Long id) {
return new CommentDto(commentService.deleteComment(id));
}
@DeleteMapping
public void deleteAllComments(){
commentService.deleteAllComments();
}
}

View File

@ -0,0 +1,23 @@
package com.webproglabs.lab1.lab34.controller;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Comment;
public class CommentDto {
private Long id;
private String text;
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 String getAuthor() {return authorLogin;}
}

View File

@ -0,0 +1,64 @@
package com.webproglabs.lab1.lab34.controller;
import com.webproglabs.lab1.WebConfiguration;
import com.webproglabs.lab1.lab34.services.PostService;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/post")
public class PostController {
private final PostService postService;
public PostController(PostService postService) {
this.postService = postService;
}
@GetMapping("/{id}")
public PostDto getPost(@PathVariable Long id) {
return new PostDto(postService.findPost(id));
}
@GetMapping
public List<PostDto> getPosts() {
return postService.findAllPosts().stream()
.map(PostDto::new)
.toList();
}
@GetMapping("/find")
public List<PostDto> getFilteredPosts(@RequestParam("text") String text) {
return postService.findFilteredPosts(text).stream()
.map(PostDto::new)
.toList();
}
@PostMapping
public PostDto createPost(
@RequestParam("text") String text,
@RequestParam("authorId") Long authorId
)
{
return new PostDto(postService.addPost(text, new ArrayList<>(),authorId));
}
@PutMapping("/{id}")
public PostDto updatePost(
@PathVariable Long id,
@RequestParam("text") String text
)
{
return new PostDto(postService.updatePost(id, text));
}
@DeleteMapping("/{id}")
public PostDto deletePost (@PathVariable Long id) {
return new PostDto(postService.deletePost(id));
}
@DeleteMapping
public void deleteAllPosts() {
postService.deleteAllPosts();
}
}

View File

@ -0,0 +1,34 @@
package com.webproglabs.lab1.lab34.controller;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import java.util.ArrayList;
import java.util.List;
public class PostDto {
private Long id;
private String text;
private List<CommentDto> comments = new ArrayList<>();
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();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public long getId() {
return id;
}
public String getText() {return text;}
public List<CommentDto> getComments() {return comments;}
public String getAuthor() {return authorLogin;}
}

View File

@ -0,0 +1,88 @@
package com.webproglabs.lab1.lab34.controller;
import com.webproglabs.lab1.WebConfiguration;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.model.UserRole;
import com.webproglabs.lab1.lab34.services.ProfileService;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping(WebConfiguration.REST_API + "/profile")
public class ProfileController {
public static final String URL_LOGIN = "/jwt/login";
private final ProfileService profileService;
public ProfileController(ProfileService profileService) {
this.profileService = profileService;
}
@GetMapping("/{id}")
public ProfileDto getProfile(@PathVariable Long id) {
return new ProfileDto(profileService.findUser(id));
}
@GetMapping("/find/{login}")
public ProfileDto getProfileByLogin(@PathVariable String login) {
return new ProfileDto(profileService.findByLogin(login));
}
@GetMapping
public List<ProfileDto> getProfiles() {
return profileService.findAllUsers().stream()
.map(ProfileDto::new)
.toList();
}
@PostMapping
public ProfileDto createProfile(
@RequestParam("login") String login,
@RequestParam("password") String password
)
{
return new ProfileDto(profileService.addUser(login, password, new ArrayList<>(),new ArrayList<>() ));
}
@PutMapping("/{id}")
public ProfileDto updateProfile(
@PathVariable Long id,
@RequestParam("login") String login,
@RequestParam("password") String password
)
{
return new ProfileDto(profileService.updateUser(id, login, password));
}
@DeleteMapping("/{id}")
public ProfileDto deleteProfile (@PathVariable Long id) {
return new ProfileDto(profileService.deleteUser(id));
}
@DeleteMapping
public void deleteAllProfiles() {
profileService.deleteAllUsers();
}
@PostMapping(URL_LOGIN)
public String login(@RequestBody @Valid ProfileDto userDto) {
return profileService.loginAndGetToken(userDto);
}
// этот метод юзать для проверки на администраторсткую роль вместо старой проверки по логину админа ЛОЛ
//
@GetMapping("role/{token}")
public String getRoleByToken(@PathVariable String token) {
var userDetails = profileService.loadUserByToken(token);
Profile user = profileService.findByLogin(userDetails.getUsername());
if (user != null) {
return user.getRole().toString();
}
return null;
}
}

View File

@ -0,0 +1,50 @@
package com.webproglabs.lab1.lab34.controller;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.model.UserRole;
import java.util.ArrayList;
import java.util.List;
public class ProfileDto {
private Long id;
private String login;
private String password;
private List<CommentDto> comments = new ArrayList<>();
private List<PostDto> posts = new ArrayList<>();
private UserRole role;
public ProfileDto(){}
public ProfileDto(Profile profile){
this.id = profile.getId();
this.login = profile.getLogin();
this.password = profile.getPassword();
this.role = profile.getRole();
for(Comment comment: profile.getComments()){
comments.add(new CommentDto(comment));
}
for (Post post: profile.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;}
}

View File

@ -0,0 +1,121 @@
package com.webproglabs.lab1.lab34.controller.mvc_controllers;
import com.webproglabs.lab1.lab34.controller.CommentDto;
import com.webproglabs.lab1.lab34.controller.PostDto;
import com.webproglabs.lab1.lab34.controller.ProfileDto;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.services.CommentService;
import com.webproglabs.lab1.lab34.services.PostService;
import com.webproglabs.lab1.lab34.services.ProfileService;
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.*;
import java.util.ArrayList;
@Controller
@RequestMapping("/feed")
public class FeedMvcController {
private final ProfileService profileService;
private final PostService postService;
private final CommentService commentService;
public FeedMvcController(ProfileService profileService, PostService postService, CommentService commentService) {
this.profileService = profileService;
this.postService = postService;
this.commentService = commentService;
}
@GetMapping
public String getFeedPage(Model model) {
UserDetails principal = (UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
var user = profileService.findByLogin(principal.getUsername());
if (user != null) {
return "redirect:/feed/" + user.getId().toString();
}
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
return "feed";
}
@GetMapping(value = {"/{id}"})
public String getFeedPageAuthorized(@PathVariable Long id, Model model) {
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
model.addAttribute("selectedProfile", new ProfileDto(profileService.findUser(id)));
return "feedPosts";
}
@GetMapping(value= {"/filter/{id}/"})
public String getFeedPageFiltered(@PathVariable Long id, @RequestParam(value="searchField") String searchField, Model model) {
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("posts", postService.findFilteredPosts(searchField).stream().map(PostDto::new).toList());
model.addAttribute("selectedProfile", new ProfileDto(profileService.findUser(id)));
return "feedPosts";
}
@PostMapping(value={"/post/{id}/"})
public String createPost(@PathVariable Long id, @RequestParam(value="postInputField") String postInputField) {
postService.addPost(postInputField, new ArrayList<>(), id);
return "redirect:/feed/" + id.toString();
}
@PostMapping(value = {"/deletePost/{id}/{authorId}"})
public String deletePost(@PathVariable Long id, @PathVariable Long authorId) {
postService.deletePost(id);
return "redirect:/feed/" + authorId.toString();
}
@GetMapping(value = {"postModal/{id}/{authorId}"})
public String getPostEditModal(@PathVariable Long id,@PathVariable Long authorId, Model model) {
model.addAttribute("selectedPost", new PostDto(postService.findPost(id)));
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
model.addAttribute("selectedProfile", new ProfileDto(profileService.findUser(authorId)));
return "editPostModal";
}
@PostMapping(value = {"editPost/{id}/{authorId}/"})
public String editPost(@PathVariable Long id, @PathVariable Long authorId, @RequestParam(value="postEditField") String postEditField) {
postService.updatePost(id, postEditField);
return "redirect:/feed/" + authorId.toString();
}
@GetMapping(value = {"commentModal/{authorId}/{postId}"})
public String getCommentModal(@PathVariable Long authorId,@PathVariable Long postId, Model model) {
model.addAttribute("selectedPost", new PostDto(postService.findPost(postId)));
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
model.addAttribute("selectedProfile", new ProfileDto(profileService.findUser(authorId)));
return "commentModal";
}
@PostMapping(value = {"comment/{authorId}/{postId}/"})
public String createComment(@PathVariable Long authorId,@PathVariable Long postId, @RequestParam(value="commentInputField") String commentInputField) {
commentService.addComment(commentInputField, authorId, postId);
return "redirect:/feed/" + authorId.toString();
}
@PostMapping(value = {"/deleteComment/{id}/{authorId}"})
public String deleteComment(@PathVariable Long id, @PathVariable Long authorId) {
commentService.deleteComment(id);
return "redirect:/feed/" + authorId.toString();
}
@GetMapping(value = {"commentEditModal/{id}/{authorId}"})
public String getCommentEditModal(@PathVariable Long id,@PathVariable Long authorId, Model model) {
model.addAttribute("selectedComment", new CommentDto(commentService.findComment(id)));
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
model.addAttribute("selectedProfile", new ProfileDto(profileService.findUser(authorId)));
return "editCommentModal";
}
@PostMapping(value = {"editComment/{authorId}/{commentId}/"})
public String editComment(@PathVariable Long authorId,@PathVariable Long commentId, @RequestParam(value="commentEditField") String commentEditField) {
commentService.updateComment(commentId, commentEditField);
return "redirect:/feed/" + authorId.toString();
}
}

View File

@ -0,0 +1,52 @@
package com.webproglabs.lab1.lab34.controller.mvc_controllers;
import com.webproglabs.lab1.lab34.controller.ProfileDto;
import com.webproglabs.lab1.lab34.model.UserRole;
import com.webproglabs.lab1.lab34.services.ProfileService;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
@Controller
@RequestMapping("/")
public class ProfileMvcController {
private final ProfileService profileService;
public ProfileMvcController(ProfileService profileService) {
this.profileService = profileService;
}
@GetMapping
public String index() {
return "default";
}
@GetMapping(value={"profiles"})
@Secured({UserRole.AsString.ADMIN})
public String getProfiles(Model model) {
model.addAttribute("profiles", profileService.findAllUsers().stream().map(ProfileDto::new).toList());
model.addAttribute("profileDto", new ProfileDto());
return "profiles";
}
@GetMapping(value = {"profile/{login}"})
public String getProfile(@PathVariable String login, Model model) {
model.addAttribute("profile", new ProfileDto(profileService.findUserByLogin(login)));
return "profilePage";
}
@PostMapping(value = {"profile/{id}"})
public String deleteProfile(@PathVariable Long id) {
profileService.deleteUser(id);
return "redirect:/profiles";
}
@PostMapping(value = {"profile/create/"})
public String createProfile(@ModelAttribute ProfileDto profileDto) {
profileService.addUser(profileDto.getLogin(), profileDto.getPassword(), new ArrayList<>(), new ArrayList<>());
return "redirect:/profiles";
}
}

View File

@ -1,17 +1,17 @@
package com.webproglabs.lab1.lab34.dto; package com.webproglabs.lab1.lab34.controller.mvc_controllers;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
public class UserSignUpDto { public class UserSignupDto {
@NotBlank @NotBlank
@Size(min = 3, max = 64) @Size(min = 3, max = 64)
private String login; private String login;
@NotBlank @NotBlank
@Size(min = 4, max = 64) @Size(min = 6, max = 64)
private String password; private String password;
@NotBlank @NotBlank
@Size(min = 4, max = 64) @Size(min = 6, max = 64)
private String passwordConfirm; private String passwordConfirm;
public String getLogin() { public String getLogin() {

View File

@ -1,9 +1,7 @@
package com.webproglabs.lab1.lab34.mvc; package com.webproglabs.lab1.lab34.controller.mvc_controllers;
import com.webproglabs.lab1.lab34.dto.UserSignUpDto; import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.model.User; import com.webproglabs.lab1.lab34.services.ProfileService;
import com.webproglabs.lab1.lab34.services.UserService;
import javax.validation.Valid;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
@ -12,25 +10,27 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import javax.validation.Valid;
@Controller @Controller
@RequestMapping(UserSignUpMvcController.SIGNUP_URL) @RequestMapping(UserSignupMvcController.SIGNUP_URL)
public class UserSignUpMvcController { public class UserSignupMvcController {
public static final String SIGNUP_URL = "/signup"; public static final String SIGNUP_URL = "/signup";
private final UserService UserService; private final ProfileService userService;
public UserSignUpMvcController(UserService userService) { public UserSignupMvcController(ProfileService userService) {
UserService = userService; this.userService = userService;
} }
@GetMapping @GetMapping
public String showSignupForm(Model model) { public String showSignupForm(Model model) {
model.addAttribute("userDto", new UserSignUpDto()); model.addAttribute("userDto", new UserSignupDto());
return "signup"; return "signup";
} }
@PostMapping @PostMapping
public String signup(@ModelAttribute("userDto") @Valid UserSignUpDto userSignupDto, public String signup(@ModelAttribute("userDto") @Valid UserSignupDto userSignupDto,
BindingResult bindingResult, BindingResult bindingResult,
Model model) { Model model) {
if (bindingResult.hasErrors()) { if (bindingResult.hasErrors()) {
@ -38,8 +38,9 @@ public class UserSignUpMvcController {
return "signup"; return "signup";
} }
try { try {
final User NewUser = UserService.createUser(userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm()); final Profile user = userService.createUser(
return "redirect:/login?created=" + NewUser.getLogin(); userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm());
return "redirect:/login?created=" + user.getLogin();
} catch (Exception e) { } catch (Exception e) {
model.addAttribute("errors", e.getMessage()); model.addAttribute("errors", e.getMessage());
return "signup"; return "signup";

View File

@ -1,36 +0,0 @@
package com.webproglabs.lab1.lab34.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Category;
import javax.validation.constraints.NotNull;
import java.util.List;
public class CategoryDto {
private Long Id;
@NotNull
private String Name;
@NotNull
private List<ProductDto> Products;
public CategoryDto(Category Category) {
this.Id = Category.getId();
this.Name = Category.getName();
this.Products = Category.getProducts().stream().map(ProductDto::new).toList();
}
public CategoryDto(){}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public List<ProductDto> getProducts() {
return Products;
}
}

View File

@ -1,33 +0,0 @@
package com.webproglabs.lab1.lab34.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Product;
import javax.validation.constraints.NotNull;
public class ProductDto {
private Long Id;
@NotNull
private String Name;
@NotNull
private Double Cost;
public ProductDto(Product Product) {
this.Id = Product.getId();
this.Name = Product.getName();
this.Cost = Product.getCost();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public Double getCost() { return Cost; }
}

View File

@ -1,38 +0,0 @@
package com.webproglabs.lab1.lab34.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.Shop;
import javax.validation.constraints.NotNull;
import java.util.List;
public class ShopDto {
private Long Id;
@NotNull
private String Name;
@NotNull
private List<ProductDto> Products;
public ShopDto(Shop Shop) {
this.Id = Shop.getId();
this.Name = Shop.getName();
this.Products = Shop.getProducts().stream().map(ProductDto::new).toList();
}
public ShopDto() {}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public void setName(String name) {
this.Name = name;
}
public List<ProductDto> getProducts() {
return Products;
}
}

View File

@ -1,52 +0,0 @@
package com.webproglabs.lab1.lab34.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.webproglabs.lab1.lab34.model.User;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
import javax.validation.constraints.NotNull;
import java.util.List;
public class UserDto {
private Long Id;
@NotNull
private String Login;
@NotNull
private String Password;
@NotNull
private List<ProductDto> Products;
@NotNull
private UserRole Role;
public UserDto(User User) {
this.Id = User.getId();
this.Login = User.getLogin();
this.Password = User.getPassword();
this.Role = User.getRole();
this.Products = User.getProducts().stream().map(ProductDto::new).toList();
}
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
public Long getId() {
return Id;
}
public String getLogin() {
return Login;
}
public String getPassword() {
return Password;
}
public List<ProductDto> getProducts() {
return Products;
}
public UserRole getRole() {
return Role;
}
}

View File

@ -0,0 +1,11 @@
package com.webproglabs.lab1.lab34.jwt;
public class JwtException extends RuntimeException {
public JwtException(Throwable throwable) {
super(throwable);
}
public JwtException(String message) {
super(message);
}
}

View File

@ -0,0 +1,72 @@
package com.webproglabs.lab1.lab34.jwt;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webproglabs.lab1.lab34.services.ProfileService;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class JwtFilter extends GenericFilterBean {
private static final String AUTHORIZATION = "Authorization";
public static final String TOKEN_BEGIN_STR = "Bearer ";
private final ProfileService userService;
public JwtFilter(ProfileService userService) {
this.userService = userService;
}
private String getTokenFromRequest(HttpServletRequest request) {
String bearer = request.getHeader(AUTHORIZATION);
if (StringUtils.hasText(bearer) && bearer.startsWith(TOKEN_BEGIN_STR)) {
return bearer.substring(TOKEN_BEGIN_STR.length());
}
return null;
}
private void raiseException(ServletResponse response, int status, String message) throws IOException {
if (response instanceof final HttpServletResponse httpResponse) {
httpResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
httpResponse.setStatus(status);
final byte[] body = new ObjectMapper().writeValueAsBytes(message);
response.getOutputStream().write(body);
}
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof final HttpServletRequest httpRequest) {
final String token = getTokenFromRequest(httpRequest);
if (StringUtils.hasText(token)) {
try {
final UserDetails user = userService.loadUserByToken(token);
final UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
} catch (JwtException e) {
raiseException(response, HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
} catch (Exception e) {
e.printStackTrace();
raiseException(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
String.format("Internal error: %s", e.getMessage()));
return;
}
}
}
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,27 @@
package com.webproglabs.lab1.lab34.jwt;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "jwt", ignoreInvalidFields = true)
public class JwtProperties {
private String devToken = "";
private Boolean isDev = true;
public String getDevToken() {
return devToken;
}
public void setDevToken(String devToken) {
this.devToken = devToken;
}
public Boolean isDev() {
return isDev;
}
public void setDev(Boolean dev) {
isDev = dev;
}
}

View File

@ -0,0 +1,107 @@
package com.webproglabs.lab1.lab34.jwt;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.Optional;
import java.util.UUID;
@Component
public class JwtProvider {
private final static Logger LOG = LoggerFactory.getLogger(JwtProvider.class);
private final static byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
private final static String ISSUER = "auth0";
private final Algorithm algorithm;
private final JWTVerifier verifier;
public JwtProvider(JwtProperties jwtProperties) {
if (!jwtProperties.isDev()) {
LOG.info("Generate new JWT key for prod");
try {
final MessageDigest salt = MessageDigest.getInstance("SHA-256");
salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
LOG.info("Use generated JWT key for prod \n{}", bytesToHex(salt.digest()));
algorithm = Algorithm.HMAC256(bytesToHex(salt.digest()));
} catch (NoSuchAlgorithmException e) {
throw new JwtException(e);
}
} else {
LOG.info("Use default JWT key for dev \n{}", jwtProperties.getDevToken());
algorithm = Algorithm.HMAC256(jwtProperties.getDevToken());
}
verifier = JWT.require(algorithm)
.withIssuer(ISSUER)
.build();
}
private static String bytesToHex(byte[] bytes) {
byte[] hexChars = new byte[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars, StandardCharsets.UTF_8);
}
public String generateToken(String login) {
final Date issueDate = Date.from(LocalDate.now()
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
final Date expireDate = Date.from(LocalDate.now()
.plusDays(15)
.atStartOfDay(ZoneId.systemDefault())
.toInstant());
return JWT.create()
.withIssuer(ISSUER)
.withIssuedAt(issueDate)
.withExpiresAt(expireDate)
.withSubject(login)
.sign(algorithm);
}
private DecodedJWT validateToken(String token) {
try {
return verifier.verify(token);
} catch (JWTVerificationException e) {
throw new JwtException(String.format("Token verification error: %s", e.getMessage()));
}
}
public boolean isTokenValid(String token) {
if (!StringUtils.hasText(token)) {
return false;
}
try {
validateToken(token);
return true;
} catch (JwtException e) {
LOG.error(e.getMessage());
return false;
}
}
public Optional<String> getLoginFromToken(String token) {
try {
return Optional.ofNullable(validateToken(token).getSubject());
} catch (JwtException e) {
LOG.error(e.getMessage());
return Optional.empty();
}
}
}

View File

@ -1,77 +0,0 @@
package com.webproglabs.lab1.lab34.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
@Column(unique = true)
private String Name;
@OneToMany(mappedBy = "Category")
private List<Product> Products = new ArrayList<>();
public Category(String Name) {
this.Name = Name;
}
public Category(){}
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public List<Product> getProducts() {
return Products;
}
public void setName(String Name) {
this.Name = Name;
}
public void addProduct(Product Product) {
this.Products.add(Product);
Product.setCategory(this);
}
public void removeProduct(Product Product) {
this.Products.remove(Product);
Product.setCategory(null);
}
public void setProducts (List<Product> Products) {
this.Products = Products;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Category category = (Category) o;
return Objects.equals(Id, category.Id);
}
@Override
public int hashCode() {
return Objects.hash(Id);
}
@Override
public String toString() {
return "Category{" +
"Id=" + Id +
", Name='" + Name +
'}';
}
}

View File

@ -0,0 +1,81 @@
package com.webproglabs.lab1.lab34.model;
import javax.persistence.*;
import java.util.Objects;
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String text;
@ManyToOne()
private Profile owner;
@ManyToOne()
private Post post;
public Comment(){};
public Comment(String text, Profile 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 Profile getOwner() {
return owner;
}
public void setOwner(Profile 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() + '\'' +
'}';
}
}

View File

@ -0,0 +1,90 @@
package com.webproglabs.lab1.lab34.model;
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 Profile author;
public Post(){}
public Post(String text, Profile author, List<Comment> comments) {
this.text = text;
this.author = author;
for (int i = 0; i < comments.size(); i++) {
addComment(comments.get(i));
}
}
public Long getId() {
return id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Profile getAuthor() {
return author;
}
public void setAuthor(Profile author) {
this.author.getPosts().remove(this);
this.author = author;
if (!author.getPosts().contains(this)) {
author.getPosts().add(this);
}
}
public List<Comment> getComments() { return comments; }
public int getCommentsSize() {
if (comments == null) return 0;
else return comments.size();
}
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() + '\'' +
", comments='" + getCommentsSize() + '\'' +
'}';
}
}

View File

@ -1,103 +0,0 @@
package com.webproglabs.lab1.lab34.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
private String Name;
public Double Cost;
@ManyToOne()
private Shop Shop;
@ManyToOne()
private Category Category;
@ManyToMany()
private List<User> Users = new ArrayList<>();
public Product (String Name, Double Cost, Shop Shop, Category Category) {
this.Name = Name;
this.Shop = Shop;
this.Cost = Cost;
this.Category = Category;
}
public Product(){}
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public Double getCost(){ return Cost; }
public Shop getShop() {
return Shop;
}
public Category getCategory() {
return Category;
}
public List<User> getUsers() {
return Users;
}
public void setName(String Name) {
this.Name = Name;
}
public void setCost(Double Cost) { this.Cost = Cost; }
public void setShop(Shop Shop) {
this.Shop.removeProduct(this);
Shop.addProduct(this);
}
public void setCategory(Category Category) {
this.Category.removeProduct(this);
Category.addProduct(this);
}
public void addUser(User User) {
Users.add(User);
}
public void removeUser(User User) {
Users.remove(User);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Objects.equals(Id, product.Id);
}
@Override
public int hashCode() {
return Objects.hash(Id);
}
@Override
public String toString() {
return "Product{" +
"Id=" + Id +
", name='" + Name +
'}';
}
}

View File

@ -0,0 +1,133 @@
package com.webproglabs.lab1.lab34.model;
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="tab_user")
public class Profile {
@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 = 6, max = 64)
private String password;
private UserRole role;
public UserRole getRole() {
return 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 Profile(){}
public Profile(String login, String password, List<Comment> comments, List<Post> posts) {
this.login = login;
this.password=password;
this.role = UserRole.USER;
for (int i = 0; i < comments.size(); i++) {
addComment(comments.get(i));
}
for (int i = 0; i < posts.size(); i++) {
addPost(posts.get(i));
}
};
public Profile(String login, String password, List<Comment> comments, List<Post> posts, UserRole role) {
this.login = login;
this.password=password;
this.role = role;
for (int i = 0; i < comments.size(); i++) {
addComment(comments.get(i));
}
for (int i = 0; i < posts.size(); i++) {
addPost(posts.get(i));
}
};
public Long getId() {
return id;
}
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 List<Comment> getComments() { return comments; }
public List<Post> getPosts() {return posts; }
public int getCommentsSize() {
if (comments == null) return 0;
else return comments.size();
}
public int getPostsSize() {
if (posts == null) return 0;
else return posts.size();
}
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;
Profile user = (Profile) 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 + '\'' +
", comments='" + getCommentsSize() + '\'' +
", comments='" + getPostsSize() + '\'' +
'}';
}
}

View File

@ -1,75 +0,0 @@
package com.webproglabs.lab1.lab34.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Entity
public class Shop {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long Id;
@Column(unique = true)
private String Name;
@OneToMany(mappedBy = "Shop")
private List<Product> Products = new ArrayList<>();
public Shop(String Name) {
this.Name = Name;
}
public Shop(){}
public Long getId() {
return Id;
}
public String getName() {
return Name;
}
public List<Product> getProducts() {
return Products;
}
public void setName(String Name) {
this.Name = Name;
}
public void addProduct(Product Product) {
this.Products.add(Product);
Product.setShop(this);
}
public void removeProduct(Product Product) {
this.Products.remove(Product);
Product.setShop(null);
}
public void setProducts (List<Product> Products) {
this.Products = Products;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Shop shop = (Shop) o;
return Objects.equals(Id, shop.Id);
}
@Override
public int hashCode() {
return Objects.hash(Id);
}
@Override
public String toString() {
return "Shop{" +
"Id=" + Id +
", Name='" + Name +
'}';
}
}

View File

@ -1,100 +0,0 @@
package com.webproglabs.lab1.lab34.model;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
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 = 1024)
@NotBlank
@Size(min = 4, max = 64)
private String login;
@Column(nullable = false, length = 1024)
@NotBlank
@Size(min = 4, max = 64)
private String Password;
@ManyToMany(mappedBy = "Users")
private List<Product> Products = new ArrayList<>();
private UserRole Role;
public User(String login, String password, UserRole role) {
this.login = login;
this.Password = password;
this.Role = role;
}
public User(String Login, String Password) {
this(Login, Password, UserRole.USER);
}
public User() {}
public Long getId() {
return Id;
}
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 List<Product> getProducts() {
return Products;
}
public void addProduct(Product Product) {
this.Products.add(Product);
Product.addUser(this);
}
public void removeProduct(Product Product) {
this.Products.remove(Product);
Product.removeUser(this);
}
public UserRole getRole() {
return Role;
}
public void setRole(UserRole Role) {
this.Role = Role;
}
@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) && Objects.equals(login, user.login);
}
@Override
public int hashCode() {
return Objects.hash(Id, login);
}
}

View File

@ -1,11 +1,10 @@
package com.webproglabs.lab1.lab34.model.enums; package com.webproglabs.lab1.lab34.model;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
public enum UserRole implements GrantedAuthority { public enum UserRole implements GrantedAuthority {
ADMIN, ADMIN,
USER, USER;
;
private static final String PREFIX = "ROLE_"; private static final String PREFIX = "ROLE_";
@ -19,5 +18,3 @@ public enum UserRole implements GrantedAuthority {
public static final String USER = PREFIX + "USER"; public static final String USER = PREFIX + "USER";
} }
} }

View File

@ -1,57 +0,0 @@
package com.webproglabs.lab1.lab34.mvc;
import com.webproglabs.lab1.lab34.dto.ShopDto;
import com.webproglabs.lab1.lab34.model.Shop;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
import com.webproglabs.lab1.lab34.services.ShopService;
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("/shops")
public class ShopMvcController {
private final ShopService shopService;
public ShopMvcController(ShopService shopService) {
this.shopService = shopService;
}
@GetMapping
@Secured({UserRole.AsString.ADMIN})
public String getShops(Model model) {
model.addAttribute("shops", shopService.findAllShops().stream().map(ShopDto::new).toList());
model.addAttribute("shopDto", new ShopDto());
return "shops";
}
@GetMapping(value = {"/edit/{Id}"})
@Secured({UserRole.AsString.ADMIN})
public String getShopEdit(@PathVariable Long Id, Model model) {
model.addAttribute("shop", shopService.findShopById(Id));
model.addAttribute("shopDto", new ShopDto());
return "shopEdit";
}
@PostMapping(value = {"/edit/{Id}"})
@Secured({UserRole.AsString.ADMIN})
public String editShop(@PathVariable Long Id, @ModelAttribute ShopDto shopDto) {
shopService.updateShop(Id, shopDto.getName());
return "redirect:/shops";
}
@PostMapping(value = {"/create"})
@Secured({UserRole.AsString.ADMIN})
public String createShop(@ModelAttribute ShopDto shopDto) {
shopService.addShop(shopDto.getName());
return "redirect:/shops";
}
@PostMapping(value = {"/delete/{Id}"})
@Secured({UserRole.AsString.ADMIN})
public String deleteShop(@PathVariable Long Id) {
shopService.deleteShop(Id);
return "redirect:/shops";
}
}

View File

@ -1,10 +0,0 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface CategoryRepository extends JpaRepository<Category, Long> {
Optional<Category> findById(Long Id);
}

View File

@ -0,0 +1,10 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findByTextLike(String text);
}

View File

@ -0,0 +1,11 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface PostRepository extends JpaRepository<Post, Long> {
List<Post> findByTextLike(String text);
}

View File

@ -1,9 +0,0 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface ProductRepository extends JpaRepository<Product, Long> {
Optional<Product> findById(Long Id);
}

View File

@ -0,0 +1,12 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ProfileRepository extends JpaRepository<Profile, Long> {
List<Profile> findByLoginLike(String login);
Profile findOneByLoginIgnoreCase(String login);
}

View File

@ -1,9 +0,0 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.Shop;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface ShopRepository extends JpaRepository<Shop, Long> {
Optional<Shop> findById(Long Id);
}

View File

@ -1,10 +0,0 @@
package com.webproglabs.lab1.lab34.repository;
import com.webproglabs.lab1.lab34.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findById(Long Id);
Optional<User> findOneByLoginIgnoreCase(String Login);
}

View File

@ -1,86 +0,0 @@
package com.webproglabs.lab1.lab34.services;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import com.webproglabs.lab1.lab34.model.Category;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.repository.CategoryRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class CategoryService {
private final CategoryRepository CategoryRepository;
public CategoryService(CategoryRepository CategoryRepository) {
this.CategoryRepository = CategoryRepository;
}
@Transactional
public Category addCategory(String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Category Category = new Category(Name);
CategoryRepository.save(Category);
return Category;
}
@Transactional
public Category findCategoryById(Long Id) {
final Category Category = CategoryRepository.findById(Id).orElse(null);
if (Category == null) {
throw new EntityNotFoundException(String.format(" Category with id [%s] is not found", Id));
}
return Category;
}
@Transactional
public List<Category> findAllCategories(){
return CategoryRepository.findAll();
}
@Transactional
public Category updateCategory(Long Id, String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.setName(Name);
return CategoryRepository.save(CurrentCategory);
}
@Transactional
public Category deleteCategory(Long Id) {
final Category CurrentCategory = findCategoryById(Id);
CategoryRepository.delete(CurrentCategory);
return CurrentCategory;
}
@Transactional
public void deleteAllCategories() {
CategoryRepository.deleteAll();
}
@Transactional
public Product addProductToCategory(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.addProduct(Product);
CategoryRepository.save(CurrentCategory);
return Product;
}
@Transactional
public void removeProductFromCategory(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Category CurrentCategory = findCategoryById(Id);
CurrentCategory.removeProduct(Product);
CategoryRepository.save(CurrentCategory);
}
}

View File

@ -0,0 +1,102 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.repository.CommentRepository;
import com.webproglabs.lab1.lab34.repository.PostRepository;
import com.webproglabs.lab1.lab34.repository.ProfileRepository;
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 ProfileRepository profileRepository;
private final CommentRepository commentRepository;
private final PostRepository postRepository;
public CommentService(ProfileRepository profileRepository, CommentRepository commentRepository, PostRepository postRepository) {
this.profileRepository = profileRepository;
this.commentRepository = commentRepository;
this.postRepository = postRepository;
}
@Transactional
public Comment findComment(Long id) {
final Optional<Comment> comment = commentRepository.findById(id);
return comment.orElseThrow(EntityNotFoundException::new);
}
@Transactional
public List<Comment> findAllComments() {
return commentRepository.findAll();
}
@Transactional
public List<Post> findFilteredComments(String filter) {
List<Post> postList = postRepository.findByTextLike("%" + filter + "%");
List<Comment> commentList = commentRepository.findByTextLike("%" + filter + "%");
List<Post> allPosts = postRepository.findAll();
for(Post post : allPosts) {
for (Comment comm : commentList) {
if (post.getComments().contains(comm) && !(postList.contains(post))) {
postList.add(post);
}
}
}
return postList;
}
@Transactional
public Comment addComment(String text, Long profileId, Long postId) {
if (!StringUtils.hasText(text)) {
throw new IllegalArgumentException("Comment data is null or empty");
}
try{
Profile user = profileRepository.findById(profileId).get();
Post post = postRepository.findById(postId).get();
Comment comment = new Comment(text, user, post);
user.addComment(comment);
post.addComment(comment);
profileRepository.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 = findComment(id);
currentComment.setText(text);
final Profile owner = currentComment.getOwner();
profileRepository.save(owner);
final Post post = currentComment.getPost();
postRepository.save(post);
return commentRepository.save(currentComment);
}
@Transactional
public Comment deleteComment(Long id) {
final Comment currentComment = findComment(id);
commentRepository.delete(currentComment);
return currentComment;
}
@Transactional
public void deleteAllComments() {
commentRepository.deleteAll();
}
}

View File

@ -0,0 +1,90 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.repository.CommentRepository;
import com.webproglabs.lab1.lab34.repository.PostRepository;
import com.webproglabs.lab1.lab34.repository.ProfileRepository;
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 ProfileRepository profileRepository;
public PostService(PostRepository postRepository, CommentRepository commentRepository, ProfileRepository profileRepository) {
this.postRepository = postRepository;
this.commentRepository = commentRepository;
this.profileRepository = profileRepository;
}
@Transactional
public Post findPost(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> findFilteredPosts(String filter) {
List<Post> postList = postRepository.findByTextLike("%" + filter + "%");
List<Comment> commentList = commentRepository.findByTextLike("%" + filter + "%");
List<Post> allPosts = postRepository.findAll();
for(Post post : allPosts) {
for (Comment comm : commentList) {
if (post.getComments().contains(comm) && !(postList.contains(post))) {
postList.add(post);
}
}
}
return postList;
}
@Transactional
public Post addPost (String text, List<Comment> comments, Long authorId) {
if (!StringUtils.hasText(text)) {
throw new IllegalArgumentException("Post data is null or empty");
}
Profile author = profileRepository.findById(authorId).get();
Post post = new Post(text, author, comments);
author.addPost(post);
profileRepository.save(author);
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 = findPost(id);
currentPost.setText(text);
final Profile author = currentPost.getAuthor();
profileRepository.save(author);
return postRepository.save(currentPost);
}
@Transactional
public Post deletePost(Long id) {
final Post currentPost = findPost(id);
postRepository.delete(currentPost);
return currentPost;
}
@Transactional
public void deleteAllPosts() {
postRepository.deleteAll();
}
}

View File

@ -1,72 +0,0 @@
package com.webproglabs.lab1.lab34.services;
import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;
import com.webproglabs.lab1.lab34.model.Category;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.Shop;
import com.webproglabs.lab1.lab34.repository.ProductRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.List;
@Service
public class ProductService {
private final ProductRepository ProductRepository;
public ProductService(ProductRepository productRepository) {
ProductRepository = productRepository;
}
@Transactional
public Product addProduct(String Name, Double Cost, Shop Shop, Category Category) {
if (!StringUtils.hasText(Name) || Cost == null || Cost < 0 || Shop == null || Category == null) {
throw new IllegalArgumentException();
}
final Product NewProduct = new Product(Name, Cost, Shop, Category);
return ProductRepository.save(NewProduct);
}
@Transactional
public Product findProductById(Long Id) {
final Product CurrentProduct = ProductRepository.findById(Id).orElse(null);
if (CurrentProduct == null) {
throw new EntityNotFoundException(String.format(" Product with id [%s] is not found", Id));
}
return CurrentProduct;
}
@Transactional
public List<Product> findAllProducts() {
return ProductRepository.findAll();
}
@Transactional
public Product updateProduct(Long Id, String Name, Double Cost, Shop Shop, Category Category) {
final Product CurrentProduct = findProductById(Id);
if (!StringUtils.hasText(Name) || Cost == null || Cost < 0 || Shop == null || Category == null) {
throw new IllegalArgumentException();
}
CurrentProduct.setName(Name);
CurrentProduct.setCost(Cost);
CurrentProduct.setShop(Shop);
CurrentProduct.setCategory(Category);
return ProductRepository.save(CurrentProduct);
}
@Transactional
public Product deleteProduct(Long Id) {
final Product CurrentProduct = findProductById(Id);
ProductRepository.delete(CurrentProduct);
return CurrentProduct;
}
@Transactional
public void deleteAllProducts() {
ProductRepository.deleteAll();
}
}

View File

@ -0,0 +1,158 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.controller.ProfileDto;
import com.webproglabs.lab1.lab34.jwt.JwtException;
import com.webproglabs.lab1.lab34.jwt.JwtProvider;
import com.webproglabs.lab1.lab34.model.Comment;
import com.webproglabs.lab1.lab34.model.Post;
import com.webproglabs.lab1.lab34.model.Profile;
import com.webproglabs.lab1.lab34.model.UserRole;
import com.webproglabs.lab1.lab34.repository.ProfileRepository;
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.*;
@Service
public class ProfileService implements UserDetailsService {
private final ProfileRepository profileRepository;
private final PasswordEncoder passwordEncoder;
private final JwtProvider jwtProvider;
public ProfileService(ProfileRepository profileRepository, PasswordEncoder passwordEncoder, JwtProvider jwtProvider) {
this.profileRepository = profileRepository;
this.passwordEncoder = passwordEncoder;
this.jwtProvider = jwtProvider;
}
@Transactional
public Profile findUser(Long id) {
final Optional<Profile> profile = profileRepository.findById(id);
return profile.orElseThrow(EntityNotFoundException::new);
}
@Transactional
public Profile findUserByLogin(String login) {
final Optional<Profile> profile = profileRepository.findByLoginLike(login).stream().findFirst();
return profile.orElseThrow(EntityNotFoundException::new);
}
@Transactional
public List<Profile> findAllUsers() {
return profileRepository.findAll();
}
@Transactional
public Profile addUser(String login, String password, List<Comment> comments, List<Post> posts) {
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
throw new IllegalArgumentException("User data is null or empty");
}
final Profile user = new Profile(login, password, comments, posts, UserRole.USER);
return profileRepository.save(user);
}
@Transactional
public Profile addUser(String login, String password, List<Comment> comments, List<Post> posts, UserRole role) {
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
throw new IllegalArgumentException("User data is null or empty");
}
final Profile user = new Profile(login, password, comments, posts, role);
return profileRepository.save(user);
}
@Transactional
public Profile createUser(String login, String password, String passwordConfirm) throws Exception {
if (findByLogin(login) != null) {
throw new Exception("User " + login + " already exists");
}
final Profile user = new Profile(login, passwordEncoder.encode(password), new ArrayList<>(), new ArrayList<>(), UserRole.USER);
if (!Objects.equals(password, passwordConfirm)) {
throw new Exception("Passwords not equals");
}
return profileRepository.save(user);
}
@Transactional
public Profile createUser(String login, String password, String passwordConfirm, UserRole role) throws Exception {
if (findByLogin(login) != null) {
throw new Exception("User " + login + " already exists");
}
final Profile user = new Profile(login, passwordEncoder.encode(password), new ArrayList<>(), new ArrayList<>(), role);
if (!Objects.equals(password, passwordConfirm)) {
throw new Exception("Passwords not equals");
}
return profileRepository.save(user);
}
@Transactional
public Profile updateUser(Long id, String login, String password) {
if (!StringUtils.hasText(login) || !StringUtils.hasText(password)) {
throw new IllegalArgumentException("User data is null or empty");
}
final Profile currentUser = findUser(id);
currentUser.setLogin(login);
currentUser.setPassword(password);
return profileRepository.save(currentUser);
}
@Transactional
public Profile deleteUser(Long id) {
final Profile currentUser = findUser(id);
profileRepository.delete(currentUser);
return currentUser;
}
@Transactional
public void deleteAllUsers() {
profileRepository.deleteAll();
}
public Profile findByLogin(String login) {
return profileRepository.findOneByLoginIgnoreCase(login);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final Profile userEntity = findByLogin(username);
if (userEntity == null) {
throw new UsernameNotFoundException(username);
}
return new org.springframework.security.core.userdetails.User(
userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole()));
}
public String loginAndGetToken(ProfileDto userDto) {
try {
final Profile user = findByLogin(userDto.getLogin());
if (user == null) {
throw new Exception("Login not found" + userDto.getLogin());
}
if (!passwordEncoder.matches(userDto.getPassword(), user.getPassword())) {
throw new Exception("User not found" + user.getLogin());
}
return jwtProvider.generateToken(user.getLogin());
}
catch (Exception e) {
var ex = e;
return null;
}
}
public UserDetails loadUserByToken(String token) throws UsernameNotFoundException {
if (!jwtProvider.isTokenValid(token)) {
throw new JwtException("Bad token");
}
final String userLogin = jwtProvider.getLoginFromToken(token)
.orElseThrow(() -> new JwtException("Token is not contain Login"));
return loadUserByUsername(userLogin);
}
}

View File

@ -1,85 +0,0 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.Shop;
import com.webproglabs.lab1.lab34.repository.ShopRepository;
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 ShopService {
private final ShopRepository ShopRepository;
public ShopService(ShopRepository ShopRepository) {
this.ShopRepository = ShopRepository;
}
@Transactional
public Shop addShop(String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Shop Shop = new Shop(Name);
ShopRepository.save(Shop);
return Shop;
}
@Transactional
public Shop findShopById(Long Id) {
final Shop Shop = ShopRepository.findById(Id).orElse(null);
if (Shop == null) {
throw new EntityNotFoundException(String.format(" Shop with id [%s] is not found", Id));
}
return Shop;
}
@Transactional
public List<Shop> findAllShops(){
return ShopRepository.findAll();
}
@Transactional
public Shop updateShop(Long Id, String Name) {
if (!StringUtils.hasText(Name)) {
throw new IllegalArgumentException("Name is null or empty");
}
final Shop CurrentShop = findShopById(Id);
CurrentShop.setName(Name);
return ShopRepository.save(CurrentShop);
}
@Transactional
public Shop deleteShop(Long Id) {
final Shop CurrentShop = findShopById(Id);
ShopRepository.delete(CurrentShop);
return CurrentShop;
}
@Transactional
public void deleteAllShops() {
ShopRepository.deleteAll();
}
@Transactional
public Product addProductToShop(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Shop CurrentShop = findShopById(Id);
CurrentShop.addProduct(Product);
ShopRepository.save(CurrentShop);
return Product;
}
@Transactional
public void removeProductFromShop(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final Shop CurrentShop = findShopById(Id);
CurrentShop.removeProduct(Product);
ShopRepository.save(CurrentShop);
}
}

View File

@ -1,117 +0,0 @@
package com.webproglabs.lab1.lab34.services;
import com.webproglabs.lab1.lab34.model.Product;
import com.webproglabs.lab1.lab34.model.User;
import com.webproglabs.lab1.lab34.model.enums.UserRole;
import com.webproglabs.lab1.lab34.repository.UserRepository;
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;
@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) {
User CurrentUser = UserRepository.findById(Id).orElse(null);
if (CurrentUser == null) {
throw new EntityNotFoundException(String.format(" User with id [%s] is not found", Id));
}
return CurrentUser;
}
@Transactional
public User findUserByLogin(String Login) {
if (!StringUtils.hasText(Login)) {
throw new IllegalArgumentException("Login is null or empty");
}
User CurrentUser = UserRepository.findOneByLoginIgnoreCase(Login).orElse(null);
return CurrentUser;
}
@Transactional
public List<User> findAllUsers() {
return UserRepository.findAll();
}
@Transactional
public User createUser(String Login, String Password, String PasswordConfirm) {
return createUser(Login, Password, PasswordConfirm, UserRole.USER);
}
@Transactional
public User createUser(String Login, String Password, String PasswordConfirm, UserRole Role) {
if (findUserByLogin(Login) != null) {
throw new IllegalArgumentException("User " + Login + " already exists");
}
if (!Objects.equals(Password, PasswordConfirm)) {
throw new IllegalArgumentException("Passwords not equals");
}
final User NewUser = new User(Login, PasswordEncoder.encode(Password), Role);
return UserRepository.save(NewUser);
}
@Transactional
public User updateUser(Long Id, String Login, String Password, UserRole Role) {
if (!StringUtils.hasText(Login) || !StringUtils.hasText(Password)) {
throw new IllegalArgumentException("User data is null or empty");
}
final User CurrentUser = findUserById(Id);
CurrentUser.setLogin(Login);
CurrentUser.setPassword(Password);
CurrentUser.setRole(Role);
return UserRepository.save(CurrentUser);
}
@Transactional
public User deleteUser(Long Id) {
final User CurrentUser = findUserById(Id);
UserRepository.delete(CurrentUser);
return CurrentUser;
}
@Transactional
public void deleteAllUsers(){
UserRepository.deleteAll();
}
@Transactional
public void addProductToUser(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final User CurrentUser = findUserById(Id);
CurrentUser.addProduct(Product);
UserRepository.save(CurrentUser);
}
@Transactional
public void removeProductFromUser(Long Id, Product Product) {
// TODO возможно придется подключать репозиторий продуктов и там тоже сохранять
final User CurrentUser = findUserById(Id);
CurrentUser.removeProduct(Product);
UserRepository.save(CurrentUser);
}
@Override
public UserDetails loadUserByUsername(String Login) throws UsernameNotFoundException {
final User UserEntity = findUserByLogin(Login);
return new org.springframework.security.core.userdetails.User(UserEntity.getLogin(), UserEntity.getPassword(), Collections.singleton(UserEntity.getRole()));
}
}

View File

@ -1,13 +0,0 @@
package com.webproglabs.lab1.lab34.validation;
import java.util.Set;
public class ValidationException extends RuntimeException {
public <T> ValidationException(Set<String> errors) {
super(String.join("\n", errors));
}
public <T> ValidationException(String error) {
super(error);
}
}

View File

@ -1,27 +0,0 @@
package com.webproglabs.lab1.lab34.validation;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class ValidatorUtil {
private final Validator validator;
public ValidatorUtil() {
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
}
public <T> void validate(T object) {
final Set<ConstraintViolation<T>> errors = validator.validate(object);
if (!errors.isEmpty()) {
throw new ValidationException(errors.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toSet()));
}
}
}

View File

@ -0,0 +1,31 @@
<!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}/{postId}/{text} (id=${selectedProfile.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>

View File

@ -3,33 +3,44 @@
xmlns:th="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"> xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
>
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8"/>
<title>Магазин</title> <title>Лабораторная работа 5</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="/favicon.svg"> <link rel="icon" href="/favicon.svg">
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script> <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> <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/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="/webjars/font-awesome/6.1.0/css/all.min.css"/>
<link rel="stylesheet" href="/css/style.css"/> <link rel="stylesheet" href="/css/style.css"/>
</head> </head>
<body> <body>
<div> <div>
<p class='text-center m-3 h3'>Магазин</p> <p class='text-center m-3 h3'> Лабораторная работа 5</p>
</div> </div>
<div> <div>
<p class='h4 text-center'> <p class='h4 text-center'>
<a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3"> <a sec:authorize="hasRole('ROLE_ADMIN')" href="/profiles" class="text-decoration-none m-3">Профили</a>
Выход <a sec:authorize="isAuthenticated()" href="/feed/" class="text-decoration-none m-3">Лента</a>
</a> <a sec:authorize="isAuthenticated()" href="/logout" class="text-decoration-none m-3">
Выход
</a>
</p> </p>
</div> </div>
<div > <div >
<div layout:fragment="content"></div> <div layout:fragment="content"></div>
</div> </div>
</body> </body>
<script type="text/javascript">
window.onload = () => {
$('#postEdit').modal('show');
$('#commentCreate').modal('show');
$('#commentEdit').modal('show');
}
</script>
</html>

View 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=${selectedProfile.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>

View 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}/{authorId}/{text} (id=${selectedPost.id}, authorId=${selectedProfile.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>

View File

@ -4,10 +4,10 @@
layout:decorate="~{default}"> layout:decorate="~{default}">
<body> <body>
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">
<div class="alert alert-danger"> <div class="alert alert-danger">
<span th:text="${error}"></span> <span th:text="${error}"></span>
</div> </div>
<a href="/">На главную</a> <a href="/">На главную</a>
</div> </div>
</body> </body>
</html> </html>

View 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-25 ">-->
<!-- <div class="text-end mt-3">-->
<!-- <button class="btn btn-secondary dropdown-toggle ms-3 mb-3 " type="button" data-bs-toggle="dropdown" aria-expanded="false">-->
<!-- Выбор пользователя-->
<!-- </button>-->
<!-- <ul class="dropdown-menu " >-->
<!-- <li th:each="profile: ${profiles}">-->
<!-- <a class="dropdown-item" th:href="@{/feed/{id}(id=${profile.id})}" th:text="${profile.login}">-->
<!-- </a>-->
<!-- </li>-->
<!-- </ul>-->
<!-- </div>-->
<!-- </div>-->
<div layout:fragment="contentFeed"></div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,106 @@
<!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-25'>
<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-25'>
Лента
<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=${selectedProfile.id}, text=${searchField}) }" method="get">
<input th:value="${searchField}" id="searchField" name="searchField" type="text" class="mb-2" style="width: 20%" 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-25 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}/{authorId} (id=${post.id}, authorId=${selectedProfile.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}/{authorId} (id=${post.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 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/post/{id}/{text} (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>

View File

@ -4,27 +4,27 @@
layout:decorate="~{default}"> layout:decorate="~{default}">
<body> <body>
<div class="container" layout:fragment="content"> <div class="container" layout:fragment="content">
<div th:if="${param.error}" class="alert alert-danger margin-bottom"> <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>
<div class="mb-3"> <div th:if="${param.logout}" class="alert alert-success margin-bottom">
<input type="password" name="password" id="password" class="form-control" Выход успешно произведен
placeholder="Пароль" required="true"/>
</div> </div>
<button type="submit" class="btn btn-success button-fixed">Войти</button> <div th:if="${param.created}" class="alert alert-success margin-bottom">
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a> Пользователь '<span th:text="${param.created}"></span>' успешно создан
</form> </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> </div>
</body> </body>
</html> </html>

View 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-25 border p-5">
<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>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!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-25 border 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">
<form action="#" th:action="@{/profile/{id} (id=${profile.id})}" method="post" >
<button type="submit" class="btn btn-danger">Удалить</button>
</form>
</div>
</div>
</div>
</div>
<div class="modal fade" id="profileCreate" tabindex="-1" role="dialog" aria-labelledby="profileCreateLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="profileCreateLabel">Регистрация профиля</h5>
</div>
<form action="#" th:action="@{/profile/create/}" th:object="${profileDto}" method="post" class="modal-body text-center">
<p>Логин: </p>
<input th:field="${profileDto.login}" type="text" class="mb-2 form-control" required="true" />
<br>
<p>Пароль: </p>
<input th:field="${profileDto.password}" type="text" class="mb-2 form-control" required="true" />
<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>

View File

@ -1,21 +0,0 @@
<!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>Name</div>
<div th:text="${shop.name}"></div>
<form action="#" th:action="@{/shops/edit/{id} (id=${shop.id})}" th:object="${shopDto}" method="post">
<p>New Name:</p>
<input th:field="${shopDto.name}" type="text" class="mb-2 form-control" required="true" />
<button type="submit" class="" >Edit</button>
</form>
<div th:each="product: ${shop.products}">
<p th:text="${product.name}"></p>
</div>
</div>
</body>
</html>

View File

@ -1,27 +0,0 @@
<!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 th:each="shop: ${shops}">
<div th:text="${'Name: ' + shop.name}" class="m-3"></div>
<form action="#" th:action="@{/shops/delete/{id} (id=${shop.id})}" method="post">
<button type="submit" class="" >Delete</button>
</form>
<form action="#" th:action="@{/shops/edit/{id} (id=${shop.id})}" method="get">
<button type="submit" class="">Edit</button>
</form>
</div>
<form action="#" th:action="@{/shops/create}" th:object="${shopDto}" method="post">
<p>Name:</p>
<input th:field="${shopDto.name}" type="text" class="mb-2 form-control" required="true" />
<button type="submit" class="" >Add</button>
</form>
</div>
</body>
</html>

View File

@ -1,8 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" <html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}" layout:decorate="~{default}">
>
<body> <body>
<div class="container container-padding" layout:fragment="content"> <div class="container container-padding" layout:fragment="content">
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div> <div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
@ -13,11 +12,11 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<input type="password" class="form-control" th:field="${userDto.password}" <input type="password" class="form-control" th:field="${userDto.password}"
placeholder="Пароль" required="true" minlength="4" maxlength="64"/> placeholder="Пароль" required="true" minlength="6" maxlength="64"/>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<input type="password" class="form-control" th:field="${userDto.passwordConfirm}" <input type="password" class="form-control" th:field="${userDto.passwordConfirm}"
placeholder="Пароль (подтверждение)" required="true" minlength="4" maxlength="64"/> placeholder="Пароль (подтверждение)" required="true" minlength="6" maxlength="64"/>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<button type="submit" class="btn btn-success button-fixed">Создать</button> <button type="submit" class="btn btn-success button-fixed">Создать</button>