Compare commits

...

6 Commits
master ... shop

Author SHA1 Message Date
048a00a4a4 i'm done 2023-06-19 23:27:36 +04:00
fcf22c2a4d signup 2023-06-19 20:32:05 +04:00
4a64a94660 dao 2023-06-19 19:16:45 +04:00
1c8d6ccfd0 dto 2023-06-19 19:15:02 +04:00
0fb27f8d13 model 2023-06-19 19:12:35 +04:00
8ae10007bb template 2023-06-19 19:06:46 +04:00
69 changed files with 1135 additions and 6049 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,8 @@
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 com.webproglabs.lab1.lab34.model.enums.UserRole;
import com.webproglabs.lab1.lab34.mvc.UserSignUpMvcController;
import com.webproglabs.lab1.lab34.services.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
@ -17,12 +15,10 @@ 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;
@ -36,18 +32,16 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
private static final String LOGIN_URL = "/login";
public static final String SPA_URL_MASK = "/{path:[^\\.]*}";
private final ProfileService userService;
private final JwtFilter jwtFilter;
private final UserService userService;
public SecurityConfiguration(ProfileService userService) {
public SecurityConfiguration(UserService userService) {
this.userService = userService;
this.jwtFilter = new JwtFilter(userService);
createAdminOnStartup();
}
private void createAdminOnStartup() {
final String admin = "admin";
if (userService.findByLogin(admin) == null) {
if (userService.findUserByLogin(admin) == null) {
log.info("Admin user successfully created");
try {
userService.createUser(admin, admin, admin, UserRole.ADMIN);
@ -59,13 +53,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(delegatingEntryPoint());
http.headers().frameOptions().sameOrigin().and()
.cors().and()
.csrf().disable()
.authorizeRequests()
.antMatchers(UserSignupMvcController.SIGNUP_URL).permitAll()
.antMatchers(UserSignUpMvcController.SIGNUP_URL).permitAll()
.antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
.anyRequest().authenticated()
.and()

View File

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

View File

@ -1,44 +0,0 @@
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

@ -1,27 +0,0 @@
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

@ -1,35 +0,0 @@
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

@ -1,47 +0,0 @@
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

@ -1,58 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -1,61 +0,0 @@
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

@ -1,28 +0,0 @@
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

@ -1,59 +0,0 @@
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

@ -1,23 +0,0 @@
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

@ -1,64 +0,0 @@
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

@ -1,34 +0,0 @@
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

@ -1,88 +0,0 @@
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

@ -1,50 +0,0 @@
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

@ -1,121 +0,0 @@
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

@ -1,52 +0,0 @@
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

@ -0,0 +1,36 @@
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

@ -0,0 +1,33 @@
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

@ -0,0 +1,38 @@
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

@ -0,0 +1,52 @@
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

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

View File

@ -1,11 +0,0 @@
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

@ -1,72 +0,0 @@
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

@ -1,27 +0,0 @@
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

@ -1,107 +0,0 @@
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

@ -0,0 +1,77 @@
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

@ -1,81 +0,0 @@
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

@ -1,90 +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 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

@ -0,0 +1,103 @@
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

@ -1,133 +0,0 @@
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

@ -0,0 +1,75 @@
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

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

View File

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

View File

@ -0,0 +1,10 @@
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

@ -1,10 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -0,0 +1,9 @@
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

@ -1,12 +0,0 @@
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

@ -0,0 +1,9 @@
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

@ -0,0 +1,10 @@
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

@ -0,0 +1,86 @@
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

@ -1,102 +0,0 @@
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

@ -1,90 +0,0 @@
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

@ -0,0 +1,72 @@
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

@ -1,158 +0,0 @@
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

@ -0,0 +1,85 @@
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

@ -0,0 +1,117 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,27 @@
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

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

View File

@ -1,30 +0,0 @@
<!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

@ -1,32 +0,0 @@
<!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}">
<body>
<div class="container" layout:fragment="content">
<div class="alert alert-danger">
<span th:text="${error}"></span>
</div>
<a href="/">На главную</a>
<div class="alert alert-danger">
<span th:text="${error}"></span>
</div>
<a href="/">На главную</a>
</div>
</body>
</html>

View File

@ -1,32 +0,0 @@
<!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

@ -1,106 +0,0 @@
<!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}">
<body>
<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 th:if="${param.logout}" class="alert alert-success margin-bottom">
Выход успешно произведен
<div class="mb-3">
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<div th:if="${param.created}" class="alert alert-success margin-bottom">
Пользователь '<span th:text="${param.created}"></span>' успешно создан
</div>
<form th:action="@{/login}" method="post" class="container-padding">
<div class="mb-3">
<input type="text" name="username" id="username" class="form-control"
placeholder="Логин" required="true" autofocus="true"/>
</div>
<div class="mb-3">
<input type="password" name="password" id="password" class="form-control"
placeholder="Пароль" required="true"/>
</div>
<button type="submit" class="btn btn-success button-fixed">Войти</button>
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a>
</form>
<button type="submit" class="btn btn-success button-fixed">Войти</button>
<a class="btn btn-primary button-fixed" href="/signup">Регистрация</a>
</form>
</div>
</body>
</html>

View File

@ -1,29 +0,0 @@
<!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

@ -1,56 +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">
<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

@ -0,0 +1,21 @@
<!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

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