diff --git a/src/main/java/org/codiki/CodikiApplication.java b/src/main/java/org/codiki/CodikiApplication.java index c81769e..06c643f 100755 --- a/src/main/java/org/codiki/CodikiApplication.java +++ b/src/main/java/org/codiki/CodikiApplication.java @@ -8,7 +8,6 @@ import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @EnableAutoConfiguration public class CodikiApplication { - public static void main(String[] args) { SpringApplication.run(CodikiApplication.class, args); } diff --git a/src/main/java/org/codiki/account/AccountController.java b/src/main/java/org/codiki/account/AccountController.java index c44870c..e716d05 100755 --- a/src/main/java/org/codiki/account/AccountController.java +++ b/src/main/java/org/codiki/account/AccountController.java @@ -101,8 +101,8 @@ public class AccountController { } @PutMapping("/") - public void update(@RequestBody final UserDTO pUser, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { - accountService.updateUser(pUser, pRequest, pResponse, pPrincipal); + public void update(@RequestBody UserDTO pUser, HttpServletResponse pResponse, Principal pPrincipal) + throws IOException { + accountService.updateUser(pUser, pResponse, pPrincipal); } } diff --git a/src/main/java/org/codiki/account/AccountService.java b/src/main/java/org/codiki/account/AccountService.java index e178dc9..43996c0 100755 --- a/src/main/java/org/codiki/account/AccountService.java +++ b/src/main/java/org/codiki/account/AccountService.java @@ -1,17 +1,5 @@ package org.codiki.account; -import java.io.IOException; -import java.nio.file.NoSuchFileException; -import java.security.Principal; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.codiki.core.entities.dto.ImageDTO; import org.codiki.core.entities.dto.PasswordWrapperDTO; import org.codiki.core.entities.dto.UserDTO; @@ -22,38 +10,30 @@ import org.codiki.core.security.CustomAuthenticationProvider; import org.codiki.core.services.FileUploadService; import org.codiki.core.services.UserService; import org.codiki.core.utils.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + @Service public class AccountService { - /** Logger. */ - private static final Logger LOG = LoggerFactory.getLogger(FileUploadService.class); + private final CustomAuthenticationProvider authenticationProvider; + private final UserService userService; + private final UserRepository userRepository; + private final FileUploadService fileUploadService; + private final ImageRepository imageRepository; - private CustomAuthenticationProvider authenticationProvider; - - private UserService userService; - - private UserRepository userRepository; - - private FileUploadService fileUploadService; - - private ImageRepository imageRepository; - - /** - * Constructor. - * @param authenticationProvider - * @param userService - * @param userRepository - * @param fileUploadService - * @param imageRepository - */ + /** Constructor. */ public AccountService(CustomAuthenticationProvider authenticationProvider, UserService userService, UserRepository userRepository, @@ -93,8 +73,8 @@ public class AccountService { return resultCode; } - public String uploadFile(final MultipartFile pFile, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { + public String uploadFile(MultipartFile pFile, HttpServletResponse pResponse, Principal pPrincipal) + throws IOException { final String avatarFileName = fileUploadService.uploadProfileImage(pFile); final Optional connectedUser = userService.getUserByPrincipal(pPrincipal); @@ -117,8 +97,7 @@ public class AccountService { return fileUploadService.loadAvatar(pAvatarFileName); } - public List getUserImages(final HttpServletRequest pRequest, final HttpServletResponse pResponse, - final Principal pPrincipal) throws IOException { + public List getUserImages(HttpServletResponse pResponse, Principal pPrincipal) throws IOException { List result = new LinkedList<>(); final Optional connectedUser = userService.getUserByPrincipal(pPrincipal); @@ -132,7 +111,7 @@ public class AccountService { return result; } - public void signin(final User pUser, final HttpServletResponse pResponse) throws IOException { + public void signin(User pUser, HttpServletResponse pResponse) throws IOException { if(pUser.getName() == null || pUser.getEmail() == null || pUser.getPassword() == null || "".equals(pUser.getPassword().trim())) { pResponse.sendError(HttpServletResponse.SC_BAD_REQUEST); } else if(userRepository.findByEmail(pUser.getEmail()).isPresent()) { @@ -148,8 +127,7 @@ public class AccountService { } } - public void updateUser(final UserDTO pUser, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { + public void updateUser(UserDTO pUser, HttpServletResponse pResponse, Principal pPrincipal) throws IOException { final Optional connectedUserOpt = userService.getUserByPrincipal(pPrincipal); if(connectedUserOpt.isPresent()) { final User connectedUser = connectedUserOpt.get(); diff --git a/src/main/java/org/codiki/categories/CategoryController.java b/src/main/java/org/codiki/categories/CategoryController.java index 719735c..474038d 100755 --- a/src/main/java/org/codiki/categories/CategoryController.java +++ b/src/main/java/org/codiki/categories/CategoryController.java @@ -1,11 +1,7 @@ package org.codiki.categories; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; - -import org.codiki.core.entities.dto.CategoryDTO; +import com.fasterxml.jackson.annotation.JsonView; +import org.codiki.core.entities.dto.View; import org.codiki.core.entities.persistence.Category; import org.codiki.core.repositories.CategoryRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -14,22 +10,33 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + @RestController @RequestMapping("/api/categories") public class CategoryController { - - @Autowired - private CategoryRepository categoryRepository; - - @GetMapping("/{id}") - public CategoryDTO findById(@PathVariable("id") final Long pId) { - final Optional result = categoryRepository.findById(pId); - return result.isPresent() ? new CategoryDTO(result.get()) : null; + private final CategoryRepository categoryRepository; + + /** Constructor. */ + public CategoryController(CategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; } - + + @JsonView(View.CategoryDTO.class) + @GetMapping("/{id}") + public Category findById(@PathVariable("id") final Long pId, + HttpServletResponse response) { + return categoryRepository.findByIdWithSubCategories(pId) + .orElseGet(() -> { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return null; + }); + } + + @JsonView(View.CategoryDTO.class) @GetMapping("/") - public List getAll() { - return StreamSupport.stream(categoryRepository.findAll().spliterator(), false) - .map(CategoryDTO::new).collect(Collectors.toList()); + public List getAll() { + return categoryRepository.findAllWithSubCategories(); } } diff --git a/src/main/java/org/codiki/core/config/CustomErrorController.java b/src/main/java/org/codiki/core/config/CustomErrorController.java deleted file mode 100644 index f5119c2..0000000 --- a/src/main/java/org/codiki/core/config/CustomErrorController.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.codiki.core.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.servlet.error.ErrorAttributes; -import org.springframework.boot.web.servlet.error.ErrorController; -import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.context.request.ServletWebRequest; - -import javax.servlet.http.HttpServletRequest; -import java.util.Map; - -/** - * Controller that catch errors from spring rest or spring security and others, and transform them to JSON response. - */ -@RestController -@RequestMapping("/error") -public class CustomErrorController implements ErrorController { - - private final ErrorAttributes errorAttributes; - - @Autowired - public CustomErrorController(ErrorAttributes errorAttributes) { - Assert.notNull(errorAttributes, "ErrorAttributes must not be null"); - this.errorAttributes = errorAttributes; - } - - @Override - public String getErrorPath() { - return "/error"; - } - - @RequestMapping - public Map error(HttpServletRequest request){ - Map body = getErrorAttributes(request, getTraceParameter(request)); - String trace = (String) body.get("trace"); - if(trace != null){ - String[] lines = trace.split("\n\t"); - body.put("trace", lines); - } - return body; - } - - private boolean getTraceParameter(HttpServletRequest request) { - String parameter = request.getParameter("trace"); - if (parameter == null) { - return false; - } - return !"false".equals(parameter.toLowerCase()); - } - - private Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { - return errorAttributes.getErrorAttributes(new ServletWebRequest(request), includeStackTrace); - } -} \ No newline at end of file diff --git a/src/main/java/org/codiki/core/config/JpaConfiguration.java b/src/main/java/org/codiki/core/config/JpaConfiguration.java index 631435d..6c11b28 100755 --- a/src/main/java/org/codiki/core/config/JpaConfiguration.java +++ b/src/main/java/org/codiki/core/config/JpaConfiguration.java @@ -17,21 +17,11 @@ import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableJpaRepositories("org.codiki.core.repositories") @PropertySource("classpath:application.yml") public class JpaConfiguration { - - @Value("${spring.jpa.datasource.driverClassName}") - private String driverClassName; - - @Value("${spring.jpa.datasource.url}") - private String url; - - @Value("${spring.jpa.datasource.username}") - private String username; - - @Value("${spring.jpa.datasource.password}") - private String password; - @Bean(name = "dataSource") - public DataSource getDataSource() { + public DataSource getDataSource(@Value("${spring.jpa.datasource.driverClassName}") String driverClassName, + @Value("${spring.jpa.datasource.url}") String url, + @Value("${spring.jpa.datasource.username}") String username, + @Value("${spring.jpa.datasource.password}") String password) { return DataSourceBuilder.create() .username(username) .password(password) diff --git a/src/main/java/org/codiki/core/config/RobotsTxtController.java b/src/main/java/org/codiki/core/config/RobotsTxtController.java index 2475f9b..c88530c 100644 --- a/src/main/java/org/codiki/core/config/RobotsTxtController.java +++ b/src/main/java/org/codiki/core/config/RobotsTxtController.java @@ -10,7 +10,6 @@ import java.io.IOException; @RestController public class RobotsTxtController { - private static final Logger LOG = LoggerFactory.getLogger(RobotsTxtController.class); @RequestMapping(value = "/robots.txt") diff --git a/src/main/java/org/codiki/core/entities/dto/View.java b/src/main/java/org/codiki/core/entities/dto/View.java index 44dcb9b..6598d2b 100755 --- a/src/main/java/org/codiki/core/entities/dto/View.java +++ b/src/main/java/org/codiki/core/entities/dto/View.java @@ -3,4 +3,5 @@ package org.codiki.core.entities.dto; public class View { public interface UserDTO {} public interface PostDTO {} + public interface CategoryDTO {} } diff --git a/src/main/java/org/codiki/core/entities/persistence/Category.java b/src/main/java/org/codiki/core/entities/persistence/Category.java index a8dd173..edf20c4 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Category.java +++ b/src/main/java/org/codiki/core/entities/persistence/Category.java @@ -20,10 +20,12 @@ import org.codiki.core.entities.dto.CategoryDTO; import org.codiki.core.entities.dto.View; import com.fasterxml.jackson.annotation.JsonView; +import org.hibernate.annotations.Proxy; @Entity @Table(name="category") @Inheritance(strategy = InheritanceType.JOINED) +@Proxy(lazy = false) public class Category implements Serializable { private static final long serialVersionUID = 1L; @@ -32,10 +34,10 @@ public class Category implements Serializable { /* ******************* */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @JsonView(View.PostDTO.class) + @JsonView({View.PostDTO.class, View.CategoryDTO.class}) private Long id; - @JsonView(View.PostDTO.class) + @JsonView({View.PostDTO.class, View.CategoryDTO.class}) private String name; /* ******************* */ @@ -44,7 +46,8 @@ public class Category implements Serializable { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "creator_id") protected User creator; - + + @JsonView({View.CategoryDTO.class}) @OneToMany(mappedBy = "mainCategory") private List listSubCategories; diff --git a/src/main/java/org/codiki/core/entities/persistence/Comment.java b/src/main/java/org/codiki/core/entities/persistence/Comment.java index de6bb23..65d23a7 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Comment.java +++ b/src/main/java/org/codiki/core/entities/persistence/Comment.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import java.util.Date; import java.util.List; @@ -19,6 +21,7 @@ import javax.persistence.TemporalType; @Entity @Table(name="comment") +@Proxy(lazy = false) public class Comment implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/CommentHistory.java b/src/main/java/org/codiki/core/entities/persistence/CommentHistory.java index 8f314fd..224ced2 100755 --- a/src/main/java/org/codiki/core/entities/persistence/CommentHistory.java +++ b/src/main/java/org/codiki/core/entities/persistence/CommentHistory.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import java.util.Date; @@ -17,6 +19,7 @@ import javax.persistence.TemporalType; @Entity @Table(name="comment_history") +@Proxy(lazy = false) public class CommentHistory implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/Image.java b/src/main/java/org/codiki/core/entities/persistence/Image.java index 4de9f84..1677319 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Image.java +++ b/src/main/java/org/codiki/core/entities/persistence/Image.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import java.util.Date; @@ -16,6 +18,7 @@ import javax.persistence.TemporalType; @Entity @Table(name="image") +@Proxy(lazy = false) public class Image implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/Post.java b/src/main/java/org/codiki/core/entities/persistence/Post.java index 173cc1b..1b9e3a8 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Post.java +++ b/src/main/java/org/codiki/core/entities/persistence/Post.java @@ -25,9 +25,11 @@ import org.hibernate.annotations.Generated; import org.hibernate.annotations.GenerationTime; import com.fasterxml.jackson.annotation.JsonView; +import org.hibernate.annotations.Proxy; @Entity @Table(name="post") +@Proxy(lazy = false) public class Post implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/PostHistory.java b/src/main/java/org/codiki/core/entities/persistence/PostHistory.java index 7af97b5..9121956 100755 --- a/src/main/java/org/codiki/core/entities/persistence/PostHistory.java +++ b/src/main/java/org/codiki/core/entities/persistence/PostHistory.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import java.util.Date; @@ -17,6 +19,7 @@ import javax.persistence.TemporalType; @Entity @Table(name="post_history") +@Proxy(lazy = false) public class PostHistory implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/Role.java b/src/main/java/org/codiki/core/entities/persistence/Role.java index 0140581..e2749a9 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Role.java +++ b/src/main/java/org/codiki/core/entities/persistence/Role.java @@ -11,9 +11,11 @@ import javax.persistence.Table; import org.codiki.core.entities.dto.View; import com.fasterxml.jackson.annotation.JsonView; +import org.hibernate.annotations.Proxy; @Entity @Table(name="role") +@Proxy(lazy = false) public class Role implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/SubCategory.java b/src/main/java/org/codiki/core/entities/persistence/SubCategory.java index d3d81b7..974fa91 100755 --- a/src/main/java/org/codiki/core/entities/persistence/SubCategory.java +++ b/src/main/java/org/codiki/core/entities/persistence/SubCategory.java @@ -1,5 +1,8 @@ package org.codiki.core.entities.persistence; +import com.fasterxml.jackson.annotation.JsonView; +import org.hibernate.annotations.Proxy; + import java.util.List; import javax.persistence.Entity; @@ -10,6 +13,7 @@ import javax.persistence.Table; @Entity @Table(name = "sub_category") +@Proxy(lazy = false) public class SubCategory extends Category { private static final long serialVersionUID = 1L; @@ -34,4 +38,15 @@ public class SubCategory extends Category { public List getListPosts() { return listPosts; } + + /** + * {@inheritDoc Category#getListSubCategories}. + * + * This getter is overrided to set {@link JsonView} annotation to avoid Lazy initialization for subcategories. + */ + @JsonView() + @Override + public List getListSubCategories() { + return super.getListSubCategories(); + } } diff --git a/src/main/java/org/codiki/core/entities/persistence/User.java b/src/main/java/org/codiki/core/entities/persistence/User.java index 3a26310..b252861 100755 --- a/src/main/java/org/codiki/core/entities/persistence/User.java +++ b/src/main/java/org/codiki/core/entities/persistence/User.java @@ -25,9 +25,11 @@ import org.hibernate.annotations.Generated; import org.hibernate.annotations.GenerationTime; import com.fasterxml.jackson.annotation.JsonView; +import org.hibernate.annotations.Proxy; @Entity @Table(name="`user`") +@Proxy(lazy = false) public class User implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/org/codiki/core/entities/persistence/Version.java b/src/main/java/org/codiki/core/entities/persistence/Version.java index d2230e0..27abd67 100755 --- a/src/main/java/org/codiki/core/entities/persistence/Version.java +++ b/src/main/java/org/codiki/core/entities/persistence/Version.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import javax.persistence.Entity; @@ -16,6 +18,7 @@ import javax.persistence.Table; */ @Entity @Table(name="version") +@Proxy(lazy = false) public class Version implements Serializable { private static final long serialVersionUID = -8803744005903941330L; diff --git a/src/main/java/org/codiki/core/entities/persistence/VersionRevision.java b/src/main/java/org/codiki/core/entities/persistence/VersionRevision.java index c3230a9..6389c46 100755 --- a/src/main/java/org/codiki/core/entities/persistence/VersionRevision.java +++ b/src/main/java/org/codiki/core/entities/persistence/VersionRevision.java @@ -1,5 +1,7 @@ package org.codiki.core.entities.persistence; +import org.hibernate.annotations.Proxy; + import java.io.Serializable; import javax.persistence.Entity; @@ -13,6 +15,7 @@ import javax.persistence.Table; @Entity @Table(name="version_revision") +@Proxy(lazy = false) public class VersionRevision implements Serializable { private static final long serialVersionUID = 1837590467941917225L; diff --git a/src/main/java/org/codiki/core/repositories/CategoryRepository.java b/src/main/java/org/codiki/core/repositories/CategoryRepository.java index b6fc9a4..bbfb64b 100755 --- a/src/main/java/org/codiki/core/repositories/CategoryRepository.java +++ b/src/main/java/org/codiki/core/repositories/CategoryRepository.java @@ -1,14 +1,19 @@ package org.codiki.core.repositories; import java.util.List; +import java.util.Optional; import org.codiki.core.entities.persistence.Category; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @Repository public interface CategoryRepository extends CrudRepository { - @Query("SELECT c FROM Category c JOIN FETCH c.listSubCategories") + @Query("SELECT c FROM Category c LEFT JOIN FETCH c.listSubCategories WHERE c.id = :id") + Optional findByIdWithSubCategories(@Param("id") Long id); + + @Query("SELECT DISTINCT(c) FROM Category c LEFT JOIN FETCH c.listSubCategories ORDER BY c.name") List findAllWithSubCategories(); } diff --git a/src/main/java/org/codiki/core/security/CorsFilter.java b/src/main/java/org/codiki/core/security/CorsFilter.java index 091a1ee..8b772bb 100755 --- a/src/main/java/org/codiki/core/security/CorsFilter.java +++ b/src/main/java/org/codiki/core/security/CorsFilter.java @@ -19,7 +19,7 @@ import org.springframework.stereotype.Component; public class CorsFilter implements Filter { @Override - public void init(FilterConfig filterConfig) throws ServletException { + public void init(FilterConfig filterConfig) { // Do nothing } @@ -40,5 +40,4 @@ public class CorsFilter implements Filter { public void destroy() { // Do nothing } - } diff --git a/src/main/java/org/codiki/core/security/CustomAuthenticationProvider.java b/src/main/java/org/codiki/core/security/CustomAuthenticationProvider.java index e0fb2ab..ec12585 100755 --- a/src/main/java/org/codiki/core/security/CustomAuthenticationProvider.java +++ b/src/main/java/org/codiki/core/security/CustomAuthenticationProvider.java @@ -1,23 +1,21 @@ package org.codiki.core.security; -import java.util.ArrayList; - import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; +import java.util.ArrayList; + @Component public class CustomAuthenticationProvider implements AuthenticationProvider { - @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // Creation of the authentication bean with its roles Authentication auth = new UsernamePasswordAuthenticationToken(authentication.getName(), - authentication.getCredentials(), new ArrayList()); + authentication.getCredentials(), new ArrayList<>()); // Set the auth bean in spring security context SecurityContextHolder.getContext().setAuthentication(auth); @@ -29,5 +27,4 @@ public class CustomAuthenticationProvider implements AuthenticationProvider { public boolean supports(Class authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } - } diff --git a/src/main/java/org/codiki/core/security/RestAuthenticationEntryPoint.java b/src/main/java/org/codiki/core/security/RestAuthenticationEntryPoint.java index 65248cb..05d2ccc 100755 --- a/src/main/java/org/codiki/core/security/RestAuthenticationEntryPoint.java +++ b/src/main/java/org/codiki/core/security/RestAuthenticationEntryPoint.java @@ -1,15 +1,13 @@ package org.codiki.core.security; -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + /** * Authentication entry point configured in * {@link SecurityConfiguration#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)} diff --git a/src/main/java/org/codiki/core/security/SecurityConfiguration.java b/src/main/java/org/codiki/core/security/SecurityConfiguration.java index 49dcc0b..d9cb2c7 100755 --- a/src/main/java/org/codiki/core/security/SecurityConfiguration.java +++ b/src/main/java/org/codiki/core/security/SecurityConfiguration.java @@ -26,11 +26,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter { private CustomAuthenticationProvider authenticationProvider; private RestAuthenticationEntryPoint authenticationEntryPoint; - /** - * Constructor. - * @param authenticationProvider - * @param authenticationEntryPoint - */ + /** Constructor. */ public SecurityConfiguration(CustomAuthenticationProvider authenticationProvider, RestAuthenticationEntryPoint authenticationEntryPoint) { this.authenticationProvider = authenticationProvider; diff --git a/src/main/java/org/codiki/core/services/FileUploadService.java b/src/main/java/org/codiki/core/services/FileUploadService.java index fd9c2a1..49d19e0 100755 --- a/src/main/java/org/codiki/core/services/FileUploadService.java +++ b/src/main/java/org/codiki/core/services/FileUploadService.java @@ -1,15 +1,6 @@ package org.codiki.core.services; -import java.io.FileNotFoundException; -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.Optional; - import org.apache.commons.lang.RandomStringUtils; -import org.codiki.core.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -18,20 +9,31 @@ import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + @Service public class FileUploadService { /** Logger. */ private static final Logger LOG = LoggerFactory.getLogger(FileUploadService.class); /** Length of uploaded file names. */ private static final int DESTINATION_IMAGE_NAME_LENGTH = 30; - - @Value("${codiki.files.upload}") - private String folderUpload; - @Value("${codiki.files.profile-images}") - private String folderProfileImages; - @Value("${codiki.files.images}") - private String folderImages; - + + private final String folderUpload; + private final String folderProfileImages; + private final String folderImages; + + public FileUploadService(@Value("${codiki.files.upload}") String folderUpload, + @Value("${codiki.files.profile-images}") String folderProfileImages, + @Value("${codiki.files.images}")String folderImages) { + this.folderUpload = folderUpload; + this.folderProfileImages = folderProfileImages; + this.folderImages = folderImages; + } + /** * Builds the destination file name, which is a random string with 30 char * length. diff --git a/src/main/java/org/codiki/core/services/ParserService.java b/src/main/java/org/codiki/core/services/ParserService.java index 1533971..e9dbcbf 100755 --- a/src/main/java/org/codiki/core/services/ParserService.java +++ b/src/main/java/org/codiki/core/services/ParserService.java @@ -9,7 +9,6 @@ import org.springframework.stereotype.Service; @Service public class ParserService { - private static final String REG_CODE = "\\[code lg="([a-z]+)"\\](.*)\\[\\/code\\]\\n"; private static final String REG_CODE_REPLACE = "
\\2
"; private static final String REG_IMAGES = "\\[img src="([^\"| ]+)"( alt="([^\"| ]+)")? \\/\\]"; @@ -17,12 +16,12 @@ public class ParserService { private static final String REG_LINKS = "\\[link href="([^\"| ]+)" txt="([^\"| ]+)" \\/\\]"; private static final String REG_LINKS_REPLACE = "\\2"; - static final Pattern PATTERN_CODE; - static final Pattern PATTERN_CODE_REPLACE; - static final Pattern PATTERN_IMAGES; - static final Pattern PATTERN_IMAGES_REPLACE; - static final Pattern PATTERN_LINKS; - static final Pattern PATTERN_LINKS_REPLACE; + private static final Pattern PATTERN_CODE; + private static final Pattern PATTERN_CODE_REPLACE; + private static final Pattern PATTERN_IMAGES; + private static final Pattern PATTERN_IMAGES_REPLACE; + private static final Pattern PATTERN_LINKS; + private static final Pattern PATTERN_LINKS_REPLACE; static { PATTERN_CODE = Pattern.compile(REG_CODE); @@ -45,7 +44,7 @@ public class ParserService { return pSource.replace("£ø", "$"); } - protected String parseHeaders(final String pSource) { + String parseHeaders(final String pSource) { String result = pSource; for(int i = 1 ; i <= 3 ; i++) { result = parseHeadersHX(result, i); @@ -53,7 +52,7 @@ public class ParserService { return result; } - protected String parseHeadersHX(final String pSource, final int pNumHeader) { + String parseHeadersHX(final String pSource, final int pNumHeader) { String result = pSource; // (.*)(\[hX\](.*)\[\/hX\])+(.*) @@ -73,11 +72,11 @@ public class ParserService { return result; } - protected String parseBackSpaces(final String pSource) { + String parseBackSpaces(final String pSource) { return pSource.replaceAll("\r?\n", "
").replaceAll("\\[\\/code\\]", "[/code]\n"); } - protected String parseImages(final String pSource) { + String parseImages(final String pSource) { String result = pSource; Matcher matcher = PATTERN_IMAGES.matcher(result); @@ -96,7 +95,7 @@ public class ParserService { return result; } - protected String parseLinks(final String pSource) { + String parseLinks(final String pSource) { String result = pSource; Matcher matcher = PATTERN_LINKS.matcher(result); diff --git a/src/main/java/org/codiki/core/services/UserService.java b/src/main/java/org/codiki/core/services/UserService.java index c0a57e6..6a1fbb7 100755 --- a/src/main/java/org/codiki/core/services/UserService.java +++ b/src/main/java/org/codiki/core/services/UserService.java @@ -16,16 +16,19 @@ import javax.swing.text.html.Option; @Service public class UserService { private static final String MSG_BAD_CREDENTIALS = "Adresse email ou mot de passe incorrect."; - - @Autowired - private UserRepository userRepository; - + + private final UserRepository userRepository; + + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + public User checkCredentials(final String email, final String password) throws BadCredentialsException { final Optional optUser = userRepository.findByEmail(email); // If no user exists with the given email of if the given password doesn't match // to the user password, we throw an exception. - if(!optUser.isPresent() || !StringUtils.compareHash(password, optUser.get().getPassword())) { + if(optUser.isEmpty() || !StringUtils.compareHash(password, optUser.get().getPassword())) { throw new BadCredentialsException(MSG_BAD_CREDENTIALS); } diff --git a/src/main/java/org/codiki/core/utils/DateUtils.java b/src/main/java/org/codiki/core/utils/DateUtils.java index 794df71..754cf3a 100755 --- a/src/main/java/org/codiki/core/utils/DateUtils.java +++ b/src/main/java/org/codiki/core/utils/DateUtils.java @@ -7,7 +7,7 @@ import java.util.Date; import java.util.Locale; public class DateUtils { - public static final String FORMAT_DEFAULT = "dd/MM/yyyy HH:mm:ss"; + private static final String FORMAT_DEFAULT = "dd/MM/yyyy HH:mm:ss"; public static Date parseDate(String pSource, String pPattern) throws ParseException { Date result = null; @@ -27,7 +27,7 @@ public class DateUtils { return getSimpleDateFormat(FORMAT_DEFAULT).format(pDate); } - public static SimpleDateFormat getSimpleDateFormat(String pPattern) { + private static SimpleDateFormat getSimpleDateFormat(String pPattern) { SimpleDateFormat result = new SimpleDateFormat(pPattern, Locale.FRENCH); result.setLenient(false); return result; diff --git a/src/main/java/org/codiki/images/ImageController.java b/src/main/java/org/codiki/images/ImageController.java index ceb441a..6c3cbb7 100755 --- a/src/main/java/org/codiki/images/ImageController.java +++ b/src/main/java/org/codiki/images/ImageController.java @@ -52,9 +52,7 @@ public class ImageController { } @PostMapping - public ResponseEntity uploadImage(@RequestParam("file") MultipartFile pFile, - final HttpServletResponse pResponse, - final Principal pPrincipal) throws IOException { + public ResponseEntity uploadImage(@RequestParam("file") MultipartFile pFile, final Principal pPrincipal) { ResponseEntity result; try { result = ResponseEntity.status(HttpStatus.OK) diff --git a/src/main/java/org/codiki/images/ImageService.java b/src/main/java/org/codiki/images/ImageService.java index 39e7d81..afb5ea1 100755 --- a/src/main/java/org/codiki/images/ImageService.java +++ b/src/main/java/org/codiki/images/ImageService.java @@ -37,7 +37,7 @@ public class ImageService { * @param fileUploadService File upload service. * @param imageRepository Image repository. */ - public ImageService(UserService userService, + ImageService(UserService userService, UserRepository userRepository, FileUploadService fileUploadService, ImageRepository imageRepository) { @@ -86,11 +86,11 @@ public class ImageService { return fileUploadService.loadAvatar(pAvatarFileName); } - public Optional loadImage(final String pImageLink) { + Optional loadImage(final String pImageLink) { return fileUploadService.loadImage(pImageLink); } - public List getUserImages(final Principal pPrincipal) { + List getUserImages(final Principal pPrincipal) { return imageRepository.getByUserId(userService.getUserByPrincipal(pPrincipal) .map(User::getId) .orElseThrow(NoSuchElementException::new)) diff --git a/src/main/java/org/codiki/posts/PostController.java b/src/main/java/org/codiki/posts/PostController.java index 6110cef..04481f1 100755 --- a/src/main/java/org/codiki/posts/PostController.java +++ b/src/main/java/org/codiki/posts/PostController.java @@ -8,7 +8,6 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.codiki.core.entities.dto.PostDTO; @@ -19,7 +18,6 @@ import org.codiki.core.repositories.PostRepository; import org.codiki.core.services.ParserService; import org.codiki.core.services.UserService; import org.codiki.core.utils.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.PageRequest; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -35,7 +33,6 @@ import com.fasterxml.jackson.annotation.JsonView; @RestController @RequestMapping("/api/posts") public class PostController { - private static final int LIMIT_POSTS_HOME = 20; /** Service to parse post content. */ private ParserService parserService; @@ -112,14 +109,11 @@ public class PostController { @JsonView(View.PostDTO.class) @GetMapping("/myPosts") - public List getMyPosts(final HttpServletRequest pRequest, final HttpServletResponse pResponse, - final Principal pPrincipal) throws IOException { + public List getMyPosts(final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { List result = new LinkedList<>(); final Optional connectedUser = userService.getUserByPrincipal(pPrincipal); if(connectedUser.isPresent()) { -// result = postRepository.getByCreator(connectedUser.get().getId()) -// .stream().map(PostDTO::new).collect(Collectors.toList()); result = postRepository.getByCreator(connectedUser.get().getId()); } else { pResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); @@ -142,20 +136,21 @@ public class PostController { @JsonView(View.PostDTO.class) @PostMapping("/") - public Post insert(@RequestBody final PostDTO pPost, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) { - return postService.insert(pPost, pRequest, pResponse, pPrincipal).orElse(null); + public Post insert(@RequestBody final Post pPost, + final HttpServletResponse pResponse, + final Principal pPrincipal) { + pResponse.setStatus(postService.insert(pPost, pPrincipal)); + return pPost; } @PutMapping("/") - public void update(@RequestBody final Post pPost, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { - postService.update(pPost, pRequest, pResponse, pPrincipal); + public void update(@RequestBody final Post pPost, + final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { + postService.update(pPost, pResponse, pPrincipal); } @DeleteMapping("/{postKey}") - public void delete(@PathVariable("postKey") final String pPostKey, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { - postService.delete(pPostKey, pRequest, pResponse, pPrincipal); + public void delete(@PathVariable("postKey") final String pPostKey, final Principal pPrincipal) { + postService.delete(pPostKey, pPrincipal); } } diff --git a/src/main/java/org/codiki/posts/PostService.java b/src/main/java/org/codiki/posts/PostService.java index 1c67f49..0a19081 100755 --- a/src/main/java/org/codiki/posts/PostService.java +++ b/src/main/java/org/codiki/posts/PostService.java @@ -1,72 +1,59 @@ package org.codiki.posts; -import java.io.IOException; -import java.security.Principal; -import java.util.Collections; -import java.util.Date; -import java.util.LinkedList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.StringUtils; import org.codiki.core.entities.business.SearchEntity; -import org.codiki.core.entities.dto.PostDTO; import org.codiki.core.entities.persistence.Category; import org.codiki.core.entities.persistence.Post; import org.codiki.core.entities.persistence.User; import org.codiki.core.repositories.CategoryRepository; import org.codiki.core.repositories.PostRepository; +import org.codiki.core.services.IllegalAccessException; import org.codiki.core.services.UserService; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.Principal; +import java.util.*; +import java.util.stream.Collectors; + @Service public class PostService { - static final int SCORE_TITLE = 50; - - static final int SCORE_DESCRIPTION = 5; - - static final int SCORE_TEXT = 1; - - static final int SCORE_CATEGORY = 30; - - static final int SCORE_AUTHOR_NAME = 40; - - static final int SCORE_AUTHOR_EMAIL = 40; + private static final int SCORE_TITLE = 50; + private static final int SCORE_DESCRIPTION = 5; + private static final int SCORE_TEXT = 1; + private static final int SCORE_CATEGORY = 30; + private static final int SCORE_AUTHOR_NAME = 40; + private static final int SCORE_AUTHOR_EMAIL = 40; - @Autowired - private PostRepository postRepository; - - @Autowired - private CategoryRepository categoryRepository; - - @Autowired - private UserService userService; - - public Optional insert(final PostDTO pPost, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) { - Optional result = Optional.empty(); - - final Optional user = userService.getUserByPrincipal(pPrincipal); - - if(user.isPresent()) { - final Post postToSave = new Post(pPost); - postToSave.setAuthor(user.get()); - postRepository.save(postToSave); - result = Optional.of(postToSave); - } else { - pResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - } - - return result; + private final PostRepository postRepository; + + private final CategoryRepository categoryRepository; + + private final UserService userService; + + /** Constructor. */ + public PostService(PostRepository postRepository, + CategoryRepository categoryRepository, + UserService userService) { + this.postRepository = postRepository; + this.categoryRepository = categoryRepository; + this.userService = userService; + } + + public int insert(final Post pPost, final Principal pPrincipal) { + return userService.getUserByPrincipal(pPrincipal) + .map(user -> { + pPost.setCreationDate(new Date()); + pPost.setAuthor(user); + postRepository.save(pPost); + return HttpServletResponse.SC_OK; + }) + .orElse(HttpServletResponse.SC_UNAUTHORIZED); } - public void update(final Post pPost, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { + public void update(final Post pPost, final HttpServletResponse pResponse, final Principal pPrincipal) + throws IOException { final Optional connectedUser = userService.getUserByPrincipal(pPrincipal); if(connectedUser.isPresent() && connectedUser.get().getKey().equals(pPost.getAuthor().getKey())) { @@ -96,23 +83,19 @@ public class PostService { } } - public void delete(final String pPostKey, final HttpServletRequest pRequest, - final HttpServletResponse pResponse, final Principal pPrincipal) throws IOException { - final Optional postToDelete = postRepository.getByKey(pPostKey); - if(postToDelete.isPresent()) { - final Optional connectedUser = userService.getUserByPrincipal(pPrincipal); - if(connectedUser.isPresent()) { - if(connectedUser.get().getKey().equals(postToDelete.get().getAuthor().getKey())) { - postRepository.delete(postToDelete.get()); - } else { - pResponse.sendError(HttpServletResponse.SC_FORBIDDEN); - } - } else { - pResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); - } - } else { - pResponse.sendError(HttpServletResponse.SC_NOT_FOUND); + public void delete(final String pPostKey, final Principal pPrincipal){ + String userKey = userService.getUserByPrincipal(pPrincipal) + .map(User::getKey) + .orElseThrow(NoSuchElementException::new); + + Post postToDelete = postRepository.getByKey(pPostKey) + .orElseThrow(NoSuchElementException::new); + + if(postToDelete.getAuthor() == null || !postToDelete.getAuthor().getKey().equals(userKey)) { + throw new IllegalAccessException(); } + + postRepository.delete(postToDelete); } public List search(String pSearchCriteria) { @@ -123,12 +106,12 @@ public class PostService { calculateScore(e, criteriasArray); listSearchEntities.add(e); }); - Collections.sort(listSearchEntities, (e1, e2) -> e2.getScore() - e1.getScore()); + listSearchEntities.sort((e1, e2) -> e2.getScore() - e1.getScore()); return listSearchEntities.stream().map(SearchEntity::getPost).collect(Collectors.toList()); } - void calculateScore(final SearchEntity searchPost, final String[] pCriteriasArray) { + private void calculateScore(final SearchEntity searchPost, final String[] pCriteriasArray) { for(final String criteria : pCriteriasArray) { String formattedCriteria = formatForComp(criteria); @@ -141,41 +124,41 @@ public class PostService { } } - String formatForComp(final String pElem) { + private String formatForComp(final String pElem) { return StringUtils.stripAccents(pElem.toLowerCase()); } - - void calculateScoreForTitle(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForTitle(final SearchEntity pSearchPost, final String pCriteria) { if(formatForComp(pSearchPost.getPost().getTitle()).contains(pCriteria)) { pSearchPost.increaseScore(SCORE_TITLE); } } - - void calculateScoreForDescription(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForDescription(final SearchEntity pSearchPost, final String pCriteria) { final int criteriaOccurence = StringUtils.countMatches(formatForComp(pSearchPost.getPost().getDescription()), pCriteria); pSearchPost.increaseScore(criteriaOccurence * SCORE_DESCRIPTION); } - - void calculateScoreForText(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForText(final SearchEntity pSearchPost, final String pCriteria) { final int criteriaOccurence = StringUtils.countMatches(formatForComp(pSearchPost.getPost().getText()), pCriteria); pSearchPost.increaseScore(criteriaOccurence * SCORE_TEXT); } - - void calculateScoreForCategory(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForCategory(final SearchEntity pSearchPost, final String pCriteria) { if(formatForComp(pSearchPost.getPost().getCategory().getName()).contains(pCriteria)) { pSearchPost.increaseScore(SCORE_CATEGORY); } } - - void calculateScoreForAuthorName(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForAuthorName(final SearchEntity pSearchPost, final String pCriteria) { if(formatForComp(pSearchPost.getPost().getAuthor().getName()).contains(pCriteria)) { pSearchPost.increaseScore(SCORE_AUTHOR_NAME); } } - - void calculateScoreForAuthorEmail(final SearchEntity pSearchPost, final String pCriteria) { + + private void calculateScoreForAuthorEmail(final SearchEntity pSearchPost, final String pCriteria) { if(formatForComp(pSearchPost.getPost().getAuthor().getEmail()).contains(pCriteria)) { pSearchPost.increaseScore(SCORE_AUTHOR_EMAIL); } diff --git a/src/main/java/org/codiki/versionrevisions/VersionRevisionController.java b/src/main/java/org/codiki/versionrevisions/VersionRevisionController.java index a8bea5f..4d3f948 100755 --- a/src/main/java/org/codiki/versionrevisions/VersionRevisionController.java +++ b/src/main/java/org/codiki/versionrevisions/VersionRevisionController.java @@ -13,13 +13,15 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/versionrevisions") public class VersionRevisionController { + private final VersionRevisionRepository repository; + private final VersionRepository versionRepository; + + public VersionRevisionController(VersionRevisionRepository repository, + VersionRepository versionRepository) { + this.repository = repository; + this.versionRepository = versionRepository; + } - @Autowired - private VersionRevisionRepository repository; - - @Autowired - private VersionRepository versionRepository; - @GetMapping("/versions") public Iterable getVersions() { return versionRepository.findAllOrderByNumber(); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0dd5724..dc61dfe 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,8 +40,7 @@ spring: url: jdbc:postgresql://localhost:5432/codiki username: codiki password: P@ssword - # TODO: Delete all Lazy relationships and set following property to false -# open-in-view: false + open-in-view: false # Because detection is disabled you have to set correct dialect by hand. database-platform: org.hibernate.dialect.PostgreSQL9Dialect # Disable feature detection by this undocumented parameter. diff --git a/src/main/sql/update_1.2.0.sql b/src/main/sql/update_1.2.0.sql index ced5465..a2b4cef 100755 --- a/src/main/sql/update_1.2.0.sql +++ b/src/main/sql/update_1.2.0.sql @@ -3,4 +3,5 @@ INSERT INTO version (number) VALUES ('1.2.0'); INSERT INTO version_revision (version_id, text, bugfix) VALUES (4, 'Migration vers Angular 8.2.', FALSE), (4, 'Migration vers Java 11.', FALSE), -(4, 'Corrections mineures et améliorations de code.', TRUE); +(4, 'Corrections mineures et améliorations de code.', TRUE), +(4, 'Ajout d''un gestionnaire de notifications pop-ups.', FALSE); diff --git a/src/main/ts/src/assets/doc/codiki_user_manual.pdf b/src/main/ts/src/assets/doc/codiki_user_manual.pdf index 618cc85..bea6692 100644 Binary files a/src/main/ts/src/assets/doc/codiki_user_manual.pdf and b/src/main/ts/src/assets/doc/codiki_user_manual.pdf differ