Merge remote-tracking branch 'origin/main'
# Conflicts: # src/main/java/site/easystartup/web/project/service/ProjectService.java # src/main/java/site/easystartup/web/service/UserService.java
This commit is contained in:
commit
3b5a6aab84
47 files changed
+361
-245
No files matched your search
@@ -0,0 +1,15 @@
|
||||
package site.easystartup.web;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
public class EasyStartupApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(EasyStartupApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package site.easystartup.web;
|
||||
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
public class ServletInitializer extends SpringBootServletInitializer {
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(EasyStartupApplication.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package site.easystartup.web.auth.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class LoginMvcConfig implements WebMvcConfigurer {
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package site.easystartup.web.auth.config;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
private final DataSource dataSource;
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/", "/home", "/registration").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.permitAll()
|
||||
.and()
|
||||
.logout()
|
||||
.permitAll()
|
||||
.and()
|
||||
.rememberMe().userDetailsService(this.userDetailsService())
|
||||
.rememberMeServices(null)
|
||||
.tokenValiditySeconds(86400)
|
||||
.useSecureCookie(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.jdbcAuthentication()
|
||||
.dataSource(dataSource)
|
||||
.passwordEncoder(passwordEncoder)
|
||||
.usersByUsernameQuery("SELECT username, password, active FROM usr WHERE username = ?;")
|
||||
.authoritiesByUsernameQuery("SELECT u.username, ur.roles FROM usr u INNER JOIN user_role ur ON u.id = ur.user_id WHERE username = ?;");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package site.easystartup.web.auth.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import site.easystartup.web.domain.Role;
|
||||
import site.easystartup.web.domain.User;
|
||||
import site.easystartup.web.repo.UserRepo;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class RegistrationController {
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
private final UserRepo userRepo;
|
||||
|
||||
@GetMapping("/registration")
|
||||
public String registration() {
|
||||
return "registration";
|
||||
}
|
||||
|
||||
@PostMapping("/registration")
|
||||
public String addUser(User user, Model model) {
|
||||
User userFromDb = userRepo.findByUsername(user.getUsername());
|
||||
|
||||
if(userFromDb != null) {
|
||||
model.addAttribute("message", "Пользователь уже существует!");
|
||||
return "registration";
|
||||
}
|
||||
|
||||
user.setActive(true);
|
||||
user.setRoles(Collections.singleton(Role.USER));
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
|
||||
userRepo.save(user);
|
||||
|
||||
return "redirect:/login";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package site.easystartup.web.config;
|
||||
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = {"site.easystartup.web"})
|
||||
public class AppConfig {
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
@Bean
|
||||
public ModelMapper modelMapper(){
|
||||
return new ModelMapper();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package site.easystartup.web.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Controller
|
||||
public class MainController {
|
||||
@GetMapping("/")
|
||||
public String home() {
|
||||
return "home";
|
||||
}
|
||||
|
||||
@GetMapping("/about")
|
||||
public String about() {
|
||||
return "about";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package site.easystartup.web.domain;
|
||||
|
||||
public enum Role {
|
||||
USER, PREMIUM, MODER, ADMIN;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package site.easystartup.web.domain;
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
@Entity
|
||||
@Table(name = "usr")
|
||||
public class User {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
private String username;
|
||||
private String password;
|
||||
private boolean active;
|
||||
private String full_name;
|
||||
private String status;
|
||||
private String iconPath;
|
||||
private String email;
|
||||
|
||||
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "user_tag", joinColumns = @JoinColumn(name = "user_id"))
|
||||
private Set<String> tags;
|
||||
|
||||
@ElementCollection(targetClass = String.class, fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "user_profession", joinColumns = @JoinColumn(name = "user_id"))
|
||||
private Set<String> professions;
|
||||
|
||||
@ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "user_projects", joinColumns = @JoinColumn(name = "user_id"))
|
||||
private Set<Long> projects;
|
||||
|
||||
@ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Set<Role> roles;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package site.easystartup.web.forum.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.val;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import site.easystartup.web.forum.domain.Topic;
|
||||
import site.easystartup.web.forum.filter.ForumFilterService;
|
||||
import site.easystartup.web.forum.repo.TopicRepo;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class ForumController {
|
||||
private final TopicRepo topicRepo;
|
||||
|
||||
private final ForumFilterService forumFilterService;
|
||||
|
||||
@GetMapping("/forum")
|
||||
public String forumMain(Model model) {
|
||||
val topic = topicRepo.findAll();
|
||||
model.addAttribute("topics", topic);
|
||||
return "/forum";
|
||||
}
|
||||
|
||||
@GetMapping("/forum/my")
|
||||
public String forumMy(Model model) {
|
||||
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
val discussions = forumFilterService.getDiscussionsByAuthor(user.getUsername());
|
||||
model.addAttribute("discussions", discussions);
|
||||
return "/my-discussions";
|
||||
}
|
||||
|
||||
@GetMapping("/forum/new")
|
||||
public String forumNew() {
|
||||
return "topic-new";
|
||||
}
|
||||
|
||||
@PostMapping("/forum/new")
|
||||
public String forumNewTopic(@RequestParam String title,
|
||||
@RequestParam String description) {
|
||||
description = description == null ? "" : description;
|
||||
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
Topic topic = new Topic();
|
||||
topic.setTitle(title);
|
||||
topic.setDescription(description);
|
||||
topic.setAuthor(user.getUsername());
|
||||
topic.setLast_update(new Date());
|
||||
topic.setSize(0);
|
||||
topicRepo.save(topic);
|
||||
return "/forum";
|
||||
}
|
||||
|
||||
@GetMapping("/forum/{topic_id}")
|
||||
public String topicFirstPage(@PathVariable(value = "topic_id") long topic_id,
|
||||
Model model) {
|
||||
val pinned_discussions = forumFilterService.getPinnedDiscussionsByTopicId(topic_id);
|
||||
model.addAttribute("pinned_discussions", pinned_discussions);
|
||||
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList(0, 15);
|
||||
model.addAttribute("discussions", discussions);
|
||||
return "topic-first";
|
||||
}
|
||||
|
||||
@GetMapping("/forum/{topic_id}/page/{page_index}")
|
||||
public String topicPage(@PathVariable(value = "topic_id") long topic_id,
|
||||
@PathVariable(value = "topic_id") long page_index,
|
||||
Model model) {
|
||||
val pinned_discussions = forumFilterService.getPinnedDiscussionsByTopicId(topic_id);
|
||||
model.addAttribute("pinned_discussions", pinned_discussions);
|
||||
val discussions = forumFilterService.getSortedDiscussionsByTopicId(topic_id).subList(0, 15);
|
||||
model.addAttribute("discussions", discussions);
|
||||
return "topic-first";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package site.easystartup.web.forum.domain;
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
@Entity
|
||||
public class Discussion implements Comparable<Discussion>{
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
private String title;
|
||||
private String author;
|
||||
private Date date;
|
||||
private Date last_update;
|
||||
private boolean pinned;
|
||||
private DiscussionStatus status;
|
||||
private long topic;
|
||||
|
||||
@ElementCollection(targetClass = Long.class, fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "discussion_messages", joinColumns = @JoinColumn(name = "discussion_id"))
|
||||
private List<Long> messages;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
|
||||
Discussion that = (Discussion) o;
|
||||
return Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Discussion o) {
|
||||
if (getLast_update() == null || o.getLast_update() == null)
|
||||
return 0;
|
||||
return getLast_update().compareTo(o.getLast_update());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package site.easystartup.web.forum.domain;
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
@Entity
|
||||
public class DiscussionMessage {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
@Column(columnDefinition="varchar(1024)")
|
||||
private String text;
|
||||
private String sender;
|
||||
private Date date;
|
||||
private boolean edited;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
|
||||
DiscussionMessage that = (DiscussionMessage) o;
|
||||
return Objects.equals(id, that.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package site.easystartup.web.forum.domain;
|
||||
|
||||
public enum DiscussionStatus {
|
||||
OPEN, CLOSED;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package site.easystartup.web.forum.domain;
|
||||
|
||||
import lombok.*;
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
@Entity
|
||||
public class Topic {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
private String title;
|
||||
private String author;
|
||||
private int size;
|
||||
private String description;
|
||||
private Date last_update;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) return false;
|
||||
Topic topic = (Topic) o;
|
||||
return Objects.equals(id, topic.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package site.easystartup.web.forum.filter;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import site.easystartup.web.forum.domain.Discussion;
|
||||
import site.easystartup.web.forum.domain.DiscussionMessage;
|
||||
import site.easystartup.web.forum.repo.DiscussionMessageRepo;
|
||||
import site.easystartup.web.forum.repo.DiscussionRepo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||
public class ForumFilterService {
|
||||
private final DiscussionMessageRepo discussionMessageRepo;
|
||||
|
||||
private final DiscussionRepo discussionRepo;
|
||||
|
||||
public List<DiscussionMessage> getMessagesByDiscussionId(long discussionId) {
|
||||
return Lists.newArrayList(discussionMessageRepo.findAll()).stream()
|
||||
.filter(m -> m.getId() == discussionId).toList();
|
||||
}
|
||||
|
||||
public List<Discussion> getDiscussionsByAuthor(String author) {
|
||||
return Lists.newArrayList(discussionRepo.findAll()).stream()
|
||||
.filter(d -> d.getAuthor().equals(author)).toList();
|
||||
}
|
||||
|
||||
public List<Discussion> getDiscussionsByMember(String member) {
|
||||
return Lists.newArrayList(discussionRepo.findAll()).stream()
|
||||
.filter(d -> getMessagesByDiscussionId(d.getId()).stream()
|
||||
.anyMatch(m -> m.getSender().equals(member))).toList();
|
||||
}
|
||||
|
||||
public List<Discussion> getPinnedDiscussionsByTopicId(long topic_id) {
|
||||
return Lists.newArrayList(discussionRepo.findAll()).stream()
|
||||
.filter(Discussion::isPinned)
|
||||
.filter(d -> d.getTopic() == topic_id).toList();
|
||||
}
|
||||
|
||||
public List<Discussion> getSortedDiscussionsByTopicId(long topic_id) {
|
||||
List<Discussion> result = Lists.newArrayList(discussionRepo.findAll()).stream()
|
||||
.filter(d -> !d.isPinned())
|
||||
.filter(d -> d.getTopic() == topic_id).toList();
|
||||
Collections.sort(result, Discussion::compareTo);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package site.easystartup.web.forum.repo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import site.easystartup.web.forum.domain.DiscussionMessage;
|
||||
|
||||
public interface DiscussionMessageRepo extends CrudRepository<DiscussionMessage, Long> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package site.easystartup.web.forum.repo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import site.easystartup.web.forum.domain.Discussion;
|
||||
|
||||
public interface DiscussionRepo extends CrudRepository<Discussion, Long> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package site.easystartup.web.forum.repo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import site.easystartup.web.forum.domain.Topic;
|
||||
|
||||
public interface TopicRepo extends CrudRepository<Topic, Long> {
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package site.easystartup.web.project.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.modelmapper.ModelMapper;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import site.easystartup.web.project.domain.model.Project;
|
||||
import site.easystartup.web.project.domain.validation.ResponseErrorValidation;
|
||||
import site.easystartup.web.project.dto.ProjectDto;
|
||||
import site.easystartup.web.project.service.ProjectService;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Map;
|
||||
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/project")
|
||||
public class ProjectController {
|
||||
private final ProjectService projectService;
|
||||
private final ResponseErrorValidation responseErrorValidation;
|
||||
private final ModelMapper modelMapper;
|
||||
|
||||
@PostMapping("/create")
|
||||
public ModelAndView createProject(@ModelAttribute("project") ProjectDto projectDto,
|
||||
BindingResult bindingResult,
|
||||
Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
Map<String, String> errors = responseErrorValidation.mapValidationService(bindingResult);
|
||||
return modelAndView.addObject("errors", errors);
|
||||
}
|
||||
|
||||
Project project = projectService.createProject(modelMapper.map(projectDto, Project.class), principal);
|
||||
modelAndView.addObject("project", project);
|
||||
modelAndView.setViewName("project");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PatchMapping("/{projectId}/update")
|
||||
public ModelAndView updateProject(@ModelAttribute("projectUpdate") ProjectDto projectDto,
|
||||
@PathVariable("projectId") Long projectId,
|
||||
BindingResult bindingResult,
|
||||
Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
Map<String, String> errors = responseErrorValidation.mapValidationService(bindingResult);
|
||||
return modelAndView.addObject("errors", errors);
|
||||
}
|
||||
|
||||
Project projectUpdated = projectService
|
||||
.updateProject(modelMapper.map(projectDto, Project.class), projectId, principal);
|
||||
modelAndView.addObject(projectUpdated);
|
||||
modelAndView.setViewName("project");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@DeleteMapping("/{projectId}/delete")
|
||||
public ModelAndView deleteProject(@PathVariable("projectId") Long projectId,
|
||||
Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
projectService.deleteProject(projectId, principal);
|
||||
modelAndView.setViewName("redirect:/my"); // some ?
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/{projectId}")
|
||||
public ModelAndView getProject(@PathVariable("projectId") Long projectId) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("project", projectService.getProjectById(projectId));
|
||||
modelAndView.setViewName("project");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/{userId}")
|
||||
public ModelAndView getAllProjectsForUser(@PathVariable("userId") Long userId) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("projects", projectService.getAllProjectsForUser(userId));
|
||||
modelAndView.setViewName("all-projects");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/{technology}")
|
||||
public ModelAndView getAllProjectsWithTechnology(@PathVariable("technology") String technology) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("projects", projectService.getAllProjectsWithTechnology(technology));
|
||||
modelAndView.setViewName("all-projects");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@GetMapping("/my")
|
||||
public ModelAndView getAllProjectsForCurrentUser(Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject(projectService.getAllProjectsForCurrentUser(principal));
|
||||
modelAndView.setViewName("all-projects");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{nameOfPosition}")
|
||||
public ModelAndView getAllProjectsWithPosition(@PathVariable("nameOfPosition") String nameOfPosition) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("projects", projectService.getAllProjectsWithPosition(nameOfPosition));
|
||||
modelAndView.setViewName("all-projects");
|
||||
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PostMapping("/{projectId}/applay")
|
||||
public ModelAndView applayOnProject(@PathVariable("projectId") Long projectId,
|
||||
Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("message", projectService.applayOnProject(projectId, principal));
|
||||
modelAndView.addObject("project", modelMapper.map(projectService.getProjectById(projectId), ProjectDto.class));
|
||||
modelAndView.setViewName("project");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@PostMapping("/{projectId}/{participantId}")
|
||||
public ModelAndView confirmParticipant(@PathVariable("projectId") Long projectId,
|
||||
@PathVariable("participantId") Long participantId,
|
||||
Principal principal) {
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
|
||||
modelAndView.addObject("message", projectService.confirmParticipant(projectId, participantId, principal));
|
||||
modelAndView.addObject("project", projectService.getProjectById(projectId));
|
||||
modelAndView.setViewName("project");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package site.easystartup.web.project.domain.model;
|
||||
|
||||
import lombok.Data;
|
||||
import site.easystartup.web.domain.User;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "participant")
|
||||
public class Participant {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "participant_id")
|
||||
private Long participantId;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "project_id", updatable = false)
|
||||
private Project project;
|
||||
|
||||
@Column(name = "technology")
|
||||
@NotNull
|
||||
private String technology;
|
||||
|
||||
@Column(name = "name_of_position")
|
||||
private String nameOfPosition;
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
private User user;
|
||||
|
||||
@OneToMany
|
||||
private Set<User> requests;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package site.easystartup.web.project.domain.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import site.easystartup.web.domain.User;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "project")
|
||||
public class Project {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "project_id")
|
||||
private Long projectId;
|
||||
|
||||
@Column(name = "cover_link")
|
||||
private String coverLink;
|
||||
|
||||
@Column(name = "title")
|
||||
@Size(min = 3, max = 100, message = "Title should be no less 3 and no more 100 signs")
|
||||
@NotNull
|
||||
private String title;
|
||||
|
||||
@Column(name = "description")
|
||||
@Size(min = 50, message = "Description should be no less 50 signs")
|
||||
@NotNull
|
||||
private String description;
|
||||
|
||||
@Column(name = "commercial_status") // 1 - commercial, 0 - non-commercial
|
||||
private int commercialStatus;
|
||||
|
||||
@Column(name = "technology")
|
||||
@NotNull
|
||||
private String technology;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "owner_id")
|
||||
private User owner;
|
||||
|
||||
@OneToMany(mappedBy = "project", cascade = {CascadeType.ALL})
|
||||
private List<Participant> participants;
|
||||
|
||||
@Column(name = "created_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
@PrePersist
|
||||
private void createdDate() {
|
||||
this.createdDate = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package site.easystartup.web.project.domain.payload.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ResponseMessage {
|
||||
private String message;
|
||||
|
||||
public ResponseMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package site.easystartup.web.project.domain.validation;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.ObjectError;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class ResponseErrorValidation {
|
||||
|
||||
public Map<String, String> mapValidationService(BindingResult result) {
|
||||
if (result.hasErrors()) {
|
||||
Map<String, String> errorMap = new HashMap<>();
|
||||
|
||||
if (!CollectionUtils.isEmpty(result.getAllErrors())) {
|
||||
for (ObjectError error : result.getAllErrors()) {
|
||||
errorMap.put(error.getCode(), error.getDefaultMessage());
|
||||
}
|
||||
}
|
||||
|
||||
for (FieldError error : result.getFieldErrors()) {
|
||||
errorMap.put(error.getCode(), error.getDefaultMessage());
|
||||
}
|
||||
|
||||
return errorMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package site.easystartup.web.project.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
public class ParticipantDto implements Serializable {
|
||||
private final Long participantId;
|
||||
@NotNull
|
||||
private final String technology;
|
||||
private final String nameOfPosition;
|
||||
private final UserDto user;
|
||||
private final Set<UserDto> requests;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package site.easystartup.web.project.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ProjectDto implements Serializable {
|
||||
private final Long projectId;
|
||||
private final String coverLink;
|
||||
@Size(min = 3, max = 100, message = "Title should be no less 3 and no more 100 signs")
|
||||
@NotNull
|
||||
private final String title;
|
||||
@Size(min = 50, message = "Description should be no less 50 signs")
|
||||
@NotNull
|
||||
private final String description;
|
||||
private final int commercialStatus;
|
||||
@NotNull
|
||||
private final String technology;
|
||||
private final List<ParticipantDto> participants;
|
||||
private final LocalDateTime createdDate;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package site.easystartup.web.project.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import site.easystartup.web.domain.Role;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
public class UserDto implements Serializable {
|
||||
private final long id;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final boolean active;
|
||||
private final String full_name;
|
||||
private final String status;
|
||||
private final String iconPath;
|
||||
private final String email;
|
||||
private final Set<String> tags;
|
||||
private final Set<String> professions;
|
||||
private final Set<Long> projects;
|
||||
private final Set<Role> roles;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package site.easystartup.web.project.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import site.easystartup.web.project.domain.model.Project;
|
||||
|
||||
@Repository
|
||||
public interface ProjectRepo extends JpaRepository<Project, Long> {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package site.easystartup.web.project.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import site.easystartup.web.project.domain.model.Project;
|
||||
import site.easystartup.web.project.repo.ProjectRepo;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ProjectService {
|
||||
private final ProjectRepo projectRepo;
|
||||
|
||||
|
||||
public Project createProject(Project project, Principal principal) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Project updateProject(Project map, Long projectId, Principal principal) {
|
||||
}
|
||||
|
||||
public void deleteProject(Long projectId, Principal principal) {
|
||||
}
|
||||
|
||||
public Project getProjectById(Long projectId) {
|
||||
}
|
||||
|
||||
public Set<Project> getAllProjectsForUser(Long userId) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Set<Project> getAllProjectsWithTechnology(String technology) {
|
||||
}
|
||||
|
||||
public Set<Project> getAllProjectsForCurrentUser(Principal principal) {
|
||||
}
|
||||
|
||||
public Set<Project> getAllProjectsWithPosition(String nameOfPosition) {
|
||||
}
|
||||
|
||||
public Object applayOnProject(Long projectId, Principal principal) {
|
||||
}
|
||||
|
||||
public Object confirmParticipant(Long projectId, Long participantId, Principal principal) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package site.easystartup.web.repo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import site.easystartup.web.domain.User;
|
||||
|
||||
public interface UserRepo extends JpaRepository<User, Long> {
|
||||
User findByUsername(String username);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package site.easystartup.web.storage.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import site.easystartup.web.storage.service.FileLocalStorageService;
|
||||
import site.easystartup.web.storage.service.StorageService;
|
||||
|
||||
@Configuration
|
||||
public class FileConfig {
|
||||
@Bean
|
||||
@Scope("singleton")
|
||||
public StorageService storageService() {
|
||||
return new FileLocalStorageService();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package site.easystartup.web.storage.controller;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
import site.easystartup.web.storage.service.StorageFileNotFoundException;
|
||||
import site.easystartup.web.storage.service.StorageService;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
public class FileUploadController {
|
||||
|
||||
private final StorageService storageService;
|
||||
|
||||
@Autowired
|
||||
public FileUploadController(StorageService storageService) {
|
||||
this.storageService = storageService;
|
||||
}
|
||||
|
||||
@GetMapping("/upload")
|
||||
public String listUploadedFiles(Model model) {
|
||||
if(storageService.loadAll() == null) {
|
||||
model.addAttribute("message",
|
||||
"Storage is emptiy");
|
||||
return "upload";
|
||||
}
|
||||
model.addAttribute("files", storageService.loadAll().map(
|
||||
path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
|
||||
"serveFile", path.getFileName().toString()).build().toUri().toString())
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
return "upload";
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@GetMapping("/files/{filename:.+}")
|
||||
@ResponseBody
|
||||
public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
|
||||
Resource file = storageService.load(filename);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file);
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
public String handleFileUpload(@RequestParam("file") MultipartFile file,
|
||||
Model model) {
|
||||
storageService.save(file);
|
||||
model.addAttribute("message",
|
||||
"You successfully uploaded " + file.getOriginalFilename() + "!");
|
||||
|
||||
return "upload";
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler(StorageFileNotFoundException.class)
|
||||
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package site.easystartup.web.storage.service;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FileLocalStorageService implements StorageService {
|
||||
private final Path root = Paths.get("uploads");
|
||||
|
||||
public FileLocalStorageService() {
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
if(!root.toFile().exists())
|
||||
Files.createDirectory(root);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not initialize folder for upload!");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void save(MultipartFile file) {
|
||||
try {
|
||||
Files.copy(file.getInputStream(), this.root.resolve(file.getOriginalFilename()));
|
||||
} catch (Exception e) {
|
||||
System.out.println("Could not store the file. Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void saveImage(MultipartFile file, String name) {
|
||||
try {
|
||||
Files.copy(file.getInputStream(), this.root.resolve(name + ".jpg"));
|
||||
} catch (Exception e) {
|
||||
Files.delete(this.root.resolve(name + ".jpg"));
|
||||
Files.copy(file.getInputStream(), this.root.resolve(name + ".jpg"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource load(String filename) {
|
||||
try {
|
||||
Path file = root.resolve(filename);
|
||||
Resource resource = new UrlResource(file.toUri());
|
||||
if (resource.exists() || resource.isReadable()) {
|
||||
return resource;
|
||||
} else {
|
||||
throw new RuntimeException("Could not read the file!");
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void deleteAll() {
|
||||
FileSystemUtils.deleteRecursively(root.toFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Path> loadAll() {
|
||||
try {
|
||||
return Files.walk(this.root, 1).filter(path -> !path.equals(this.root)).map(this.root::relativize);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Could not load the files!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package site.easystartup.web.storage.service;
|
||||
|
||||
public class StorageFileNotFoundException extends RuntimeException {
|
||||
public StorageFileNotFoundException(String filename) {
|
||||
super("Could not find file with name " + filename);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package site.easystartup.web.storage.service;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public interface StorageService {
|
||||
void init();
|
||||
void save(MultipartFile file);
|
||||
void saveImage(MultipartFile file, String name);
|
||||
Resource load(String filename);
|
||||
void deleteAll();
|
||||
Stream<Path> loadAll();
|
||||
}
|
||||
Reference in new issue
Block a user