Save the actual version of the embryon api.
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -59,6 +59,11 @@
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
package org.codiki.login;
|
||||
package org.codiki.account;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.codiki.core.entities.dto.UserDAO;
|
||||
import org.codiki.core.entities.dto.PasswordWrapperDTO;
|
||||
import org.codiki.core.entities.dto.UserDTO;
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
import org.codiki.core.security.TokenService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/account")
|
||||
public class LoginController {
|
||||
public class AccountController {
|
||||
|
||||
private static final String HEADER_TOKEN = "token";
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
private AccountService accountService;
|
||||
|
||||
@Autowired
|
||||
private LoginService loginService;
|
||||
private TokenService tokenService;
|
||||
|
||||
|
||||
@PostMapping("/login")
|
||||
public UserDAO login(@RequestBody UserDAO pUser, HttpServletResponse response) {
|
||||
return loginService.checkCredentials(response, pUser);
|
||||
public UserDTO login(@RequestBody UserDTO pUser, HttpServletResponse response) {
|
||||
return accountService.checkCredentials(response, pUser);
|
||||
}
|
||||
|
||||
@GetMapping("/logout")
|
||||
@@ -34,4 +38,10 @@ public class LoginController {
|
||||
tokenService.removeUser(pRequest.getHeader(HEADER_TOKEN));
|
||||
}
|
||||
|
||||
@PutMapping("/changePassword")
|
||||
public boolean changePassword(@RequestBody final PasswordWrapperDTO pPasswordWrapper,
|
||||
final HttpServletRequest pRequest,
|
||||
final HttpServletResponse pResponse) {
|
||||
return accountService.changePassword(tokenService.getAuthenticatedUserByToken(pRequest), pPasswordWrapper, pResponse);
|
||||
}
|
||||
}
|
||||
69
src/main/java/org/codiki/account/AccountService.java
Normal file
69
src/main/java/org/codiki/account/AccountService.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package org.codiki.account;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.codiki.core.entities.dto.PasswordWrapperDTO;
|
||||
import org.codiki.core.entities.dto.UserDTO;
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
import org.codiki.core.repositories.UserRepository;
|
||||
import org.codiki.core.security.TokenService;
|
||||
import org.codiki.core.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AccountService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
/**
|
||||
* Check the user credentials and generate him a token if they are correct.
|
||||
*
|
||||
* @param pUser
|
||||
* The user sent from client.
|
||||
* @return The user populated with the generated token.
|
||||
* @throws AuthenticationException
|
||||
* If the credentials are wrong.
|
||||
*/
|
||||
public UserDTO checkCredentials(HttpServletResponse pResponse, UserDTO pUser) {
|
||||
UserDTO result = null;
|
||||
|
||||
Optional<User> user = userRepository.findByEmail(pUser.getEmail());
|
||||
|
||||
if(user.isPresent() && StringUtils.compareHash(pUser.getPassword(), user.get().getPassword())) {
|
||||
tokenService.addUser(user.get());
|
||||
result = new UserDTO(user.get(), true);
|
||||
} else {
|
||||
pResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean changePassword(final User pUser, final PasswordWrapperDTO pPasswordWrapper,
|
||||
final HttpServletResponse pResponse) {
|
||||
boolean result = false;
|
||||
|
||||
if(pPasswordWrapper.getNewPassword().equals(pPasswordWrapper.getConfirmPassword())) {
|
||||
// We fetch the connected user from database to get his hashed password
|
||||
final Optional<User> userFromDb = userRepository.findById(pUser.getId());
|
||||
if(userFromDb.isPresent() && StringUtils.compareHash(pPasswordWrapper.getOldPassword(),
|
||||
userFromDb.get().getPassword())) {
|
||||
result = true;
|
||||
userFromDb.get().setPassword(StringUtils.hashPassword(pPasswordWrapper.getNewPassword()));
|
||||
userRepository.save(userFromDb.get());
|
||||
} else {
|
||||
pResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
35
src/main/java/org/codiki/categories/CategoryController.java
Normal file
35
src/main/java/org/codiki/categories/CategoryController.java
Normal file
@@ -0,0 +1,35 @@
|
||||
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 org.codiki.core.entities.persistence.Category;
|
||||
import org.codiki.core.repositories.CategoryRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/categories")
|
||||
public class CategoryController {
|
||||
|
||||
@Autowired
|
||||
private CategoryRepository categoryRepository;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CategoryDTO findById(@PathVariable("id") final Long pId) {
|
||||
final Optional<Category> result = categoryRepository.findById(pId);
|
||||
return result.isPresent() ? new CategoryDTO(result.get()) : null;
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public List<CategoryDTO> getAll() {
|
||||
return StreamSupport.stream(categoryRepository.findAll().spliterator(), false)
|
||||
.map(CategoryDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -110,12 +110,14 @@ public abstract class AbstractFilter implements Filter {
|
||||
boolean isMethodFiltered(final Route pRoute, final String pRequestMethod) {
|
||||
boolean result = false;
|
||||
|
||||
if(pRoute.getMethod().isPresent()) {
|
||||
for(final HttpMethod routeMethod : pRoute.getMethod().get()) {
|
||||
if(routeMethod.name().equals(pRequestMethod)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
36
src/main/java/org/codiki/core/entities/dto/CategoryDTO.java
Normal file
36
src/main/java/org/codiki/core/entities/dto/CategoryDTO.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package org.codiki.core.entities.dto;
|
||||
|
||||
import org.codiki.core.entities.persistence.Category;
|
||||
|
||||
public class CategoryDTO {
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public CategoryDTO() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CategoryDTO(final Category pCategory) {
|
||||
this();
|
||||
id = pCategory.getId();
|
||||
name = pCategory.getName();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.codiki.core.entities.dto;
|
||||
|
||||
public class PasswordWrapperDTO {
|
||||
|
||||
private String oldPassword;
|
||||
|
||||
private String newPassword;
|
||||
|
||||
private String confirmPassword;
|
||||
|
||||
public String getOldPassword() {
|
||||
return oldPassword;
|
||||
}
|
||||
|
||||
public void setOldPassword(String oldPassword) {
|
||||
this.oldPassword = oldPassword;
|
||||
}
|
||||
|
||||
public String getNewPassword() {
|
||||
return newPassword;
|
||||
}
|
||||
|
||||
public void setNewPassword(String newPassword) {
|
||||
this.newPassword = newPassword;
|
||||
}
|
||||
|
||||
public String getConfirmPassword() {
|
||||
return confirmPassword;
|
||||
}
|
||||
|
||||
public void setConfirmPassword(String confirmPassword) {
|
||||
this.confirmPassword = confirmPassword;
|
||||
}
|
||||
}
|
||||
105
src/main/java/org/codiki/core/entities/dto/PostDTO.java
Normal file
105
src/main/java/org/codiki/core/entities/dto/PostDTO.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package org.codiki.core.entities.dto;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.codiki.core.entities.persistence.Post;
|
||||
|
||||
public class PostDTO {
|
||||
|
||||
private String key;
|
||||
|
||||
private String title;
|
||||
|
||||
private String text;
|
||||
|
||||
private String description;
|
||||
|
||||
private String image;
|
||||
|
||||
private Date creationDate;
|
||||
|
||||
private UserDTO author;
|
||||
|
||||
private CategoryDTO category;
|
||||
|
||||
public PostDTO() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PostDTO(final Post pPost) {
|
||||
this();
|
||||
key = pPost.getKey();
|
||||
title = pPost.getTitle();
|
||||
text = pPost.getText();
|
||||
description = pPost.getDescription();
|
||||
image = pPost.getImage();
|
||||
creationDate = pPost.getCreationDate();
|
||||
author = new UserDTO(pPost.getAuthor());
|
||||
category = new CategoryDTO(pPost.getCategory());
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(String image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
|
||||
public void setCreationDate(Date creationDate) {
|
||||
this.creationDate = creationDate;
|
||||
}
|
||||
|
||||
public UserDTO getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(UserDTO author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
public CategoryDTO getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(CategoryDTO category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import java.util.Date;
|
||||
import org.codiki.core.entities.persistence.Role;
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
|
||||
public class UserDAO {
|
||||
public class UserDTO {
|
||||
|
||||
private String key;
|
||||
|
||||
@@ -23,19 +23,25 @@ public class UserDAO {
|
||||
|
||||
private String token;
|
||||
|
||||
public UserDAO() {
|
||||
public UserDTO() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UserDAO(final User pUser) {
|
||||
public UserDTO(final User pUser) {
|
||||
key = pUser.getKey();
|
||||
name = pUser.getName();
|
||||
email = pUser.getEmail();
|
||||
image = pUser.getImage();
|
||||
inscriptionDate = pUser.getInscriptionDate();
|
||||
role = pUser.getRole();
|
||||
}
|
||||
|
||||
public UserDTO(final User pUser, final boolean pWithToken) {
|
||||
this(pUser);
|
||||
if(pWithToken) {
|
||||
token = pUser.getToken().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
@@ -14,6 +14,8 @@ import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.codiki.core.entities.dto.CategoryDTO;
|
||||
|
||||
@Entity
|
||||
@Table(name="category")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
@@ -42,6 +44,19 @@ public class Category implements Serializable {
|
||||
@OneToMany(mappedBy = "category")
|
||||
protected List<Post> listPosts;
|
||||
|
||||
/* ******************* */
|
||||
/* Constructors */
|
||||
/* ******************* */
|
||||
public Category() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Category(final CategoryDTO pCategory) {
|
||||
this();
|
||||
id = pCategory.getId();
|
||||
name = pCategory.getName();
|
||||
}
|
||||
|
||||
/* ******************* */
|
||||
/* Getters & Setters */
|
||||
/* ******************* */
|
||||
|
||||
@@ -18,7 +18,10 @@ import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.codiki.core.entities.dto.PostDTO;
|
||||
import org.codiki.core.utils.DateUtils;
|
||||
import org.hibernate.annotations.Generated;
|
||||
import org.hibernate.annotations.GenerationTime;
|
||||
|
||||
@Entity
|
||||
@Table(name="post")
|
||||
@@ -35,6 +38,8 @@ public class Post implements Serializable {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
// This annotation serves to fetch the attribute after an insert into db
|
||||
@Generated(GenerationTime.ALWAYS)
|
||||
private String key;
|
||||
|
||||
private String title;
|
||||
@@ -71,6 +76,15 @@ public class Post implements Serializable {
|
||||
super();
|
||||
}
|
||||
|
||||
public Post(final PostDTO pPost) {
|
||||
title = pPost.getTitle();
|
||||
image = pPost.getImage();
|
||||
description = pPost.getDescription();
|
||||
creationDate = new Date();
|
||||
text = pPost.getText();
|
||||
category = new Category(pPost.getCategory());
|
||||
}
|
||||
|
||||
/* ******************* */
|
||||
/* Getters & Setters */
|
||||
/* ******************* */
|
||||
|
||||
@@ -11,7 +11,7 @@ public class Token {
|
||||
private static final int DELAY = 30;
|
||||
|
||||
/** The Constant BITS_NUMBER. */
|
||||
private static final int BITS_NUMBER = 130;
|
||||
private static final int BITS_NUMBER = 1000;
|
||||
/** The Constant RADIX. */
|
||||
private static final int RADIX = 32;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.codiki.core.repositories;
|
||||
|
||||
import org.codiki.core.entities.persistence.Category;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface CategoryRepository extends CrudRepository<Category, Long> {
|
||||
|
||||
}
|
||||
@@ -1,10 +1,32 @@
|
||||
package org.codiki.core.repositories;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.codiki.core.entities.persistence.Post;
|
||||
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 PostRepository extends CrudRepository<Post, Long> {
|
||||
|
||||
@Query("SELECT p FROM Post p WHERE p.key = :postKey")
|
||||
Optional<Post> getByKey(@Param("postKey") final String pPostKey);
|
||||
|
||||
@Query(value = "SELECT * FROM post p INNER JOIN \"user\" u ON u.id = p.creator_id ORDER BY p.creation_date DESC LIMIT :limit",
|
||||
nativeQuery = true)
|
||||
List<Post> getLast(@Param("limit") final Integer pLimit);
|
||||
|
||||
@Query(value = "SELECT * FROM post p WHERE category_id = :categoryId ORDER BY creation_date DESC",
|
||||
nativeQuery = true)
|
||||
List<Post> getByCategoryId(@Param("categoryId") final Long pCategoryId);
|
||||
|
||||
@Query(value = "SELECT * FROM post WHERE creator_id = :creatorId ORDER BY creation_date DESC",
|
||||
nativeQuery = true)
|
||||
List<Post> getByCreator(@Param("creatorId") final Long pCreatorId);
|
||||
|
||||
@Query(value = "SELECT * FROM Post WHERE id = :id", nativeQuery = true)
|
||||
Optional<Post> getOne(@Param("id") final Long id);
|
||||
}
|
||||
|
||||
@@ -2,12 +2,38 @@ package org.codiki.core.repositories;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
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 UserRepository extends CrudRepository<User, Long> {
|
||||
|
||||
Optional<User> findByEmail(@Param("email") final String pEmail);
|
||||
|
||||
/**
|
||||
* Checks if the password in parameters is the passwords of the user in
|
||||
* database.
|
||||
*
|
||||
* @param pId
|
||||
* The user id.
|
||||
* @param pPassword
|
||||
* The password to check.
|
||||
* @return {@code true} if the password is the user password in database,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
@Query(value = "SELECT CASE WHEN EXISTS(" +
|
||||
" SELECT id FROM \"user\" WHERE id = :id AND password = :password" +
|
||||
") THEN TRUE ELSE FALSE END", nativeQuery = true)
|
||||
boolean checkPassword(@Param("id") final Long pId, @Param("password") final String pPassword);
|
||||
|
||||
@Query(value = "UPDATE \"user\" SET password = :password WHERE id = :id", nativeQuery = true)
|
||||
@Transactional
|
||||
@Modifying
|
||||
void updatePassword(@Param("id") final Long pId, @Param("password") final String pPassword);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import java.util.List;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -26,7 +25,7 @@ public class AuthenticationFilter extends AbstractFilter {
|
||||
@Override
|
||||
protected List<Route> getRoutes() {
|
||||
return Arrays.asList(
|
||||
new Route("\\/api\\/posts.*")
|
||||
new Route("\\/api\\/posts\\/myPosts")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,7 +33,7 @@ public class AuthenticationFilter extends AbstractFilter {
|
||||
protected void filter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
System.out.println("Token : " + request.getHeader("token"));
|
||||
|
||||
if(tokenService.isUserConnected(request.getHeader("token"))) {
|
||||
if("OPTIONS".equals(request.getMethod()) || tokenService.isUserConnected(request.getHeader("token"))) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package org.codiki.core.security;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -11,6 +15,8 @@ public class TokenService {
|
||||
/** Map of connected users. */
|
||||
private static final Map<String, User> connectedUsers;
|
||||
|
||||
private static final String HEADER_TOKEN = "token";
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
@@ -49,11 +55,15 @@ public class TokenService {
|
||||
*/
|
||||
@SuppressWarnings("unlikely-arg-type")
|
||||
private void clearExpiredUsers() {
|
||||
synchronized (this) {
|
||||
List<User> usersToRemove = new LinkedList<>();
|
||||
connectedUsers.entrySet().stream().forEach(user -> {
|
||||
if(!user.getValue().getToken().isValid()) {
|
||||
connectedUsers.remove(user).getKey();
|
||||
usersToRemove.add(user.getValue());
|
||||
}
|
||||
});
|
||||
usersToRemove.stream().forEach(connectedUsers::remove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,4 +113,8 @@ public class TokenService {
|
||||
connectedUsers.remove(pToken);
|
||||
}
|
||||
}
|
||||
|
||||
public User getAuthenticatedUserByToken(final HttpServletRequest pRequest) {
|
||||
return connectedUsers.get(pRequest.getHeader(HEADER_TOKEN));
|
||||
}
|
||||
}
|
||||
|
||||
131
src/main/java/org/codiki/core/services/ParserService.java
Normal file
131
src/main/java/org/codiki/core/services/ParserService.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package org.codiki.core.services;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.codiki.core.utils.StringUtils;
|
||||
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 = "<pre class=\"line-numbers\"><code class=\"language-\\1\">\\2</code></pre>";
|
||||
private static final String REG_IMAGES = "\\[img src="([^\"| ]+)"( alt="([^\"| ]+)")? \\/\\]";
|
||||
private static final String REG_IMAGES_REPLACE = "<img src=\"\\1\" alt=\"\\3\" />";
|
||||
private static final String REG_LINKS = "\\[link href="([^\"| ]+)" txt="([^\"| ]+)" \\/\\]";
|
||||
private static final String REG_LINKS_REPLACE = "<a href=\"\\1\">\\2</a>";
|
||||
|
||||
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;
|
||||
|
||||
static {
|
||||
PATTERN_CODE = Pattern.compile(REG_CODE);
|
||||
PATTERN_CODE_REPLACE = Pattern.compile(REG_CODE_REPLACE);
|
||||
PATTERN_IMAGES = Pattern.compile(REG_IMAGES);
|
||||
PATTERN_IMAGES_REPLACE = Pattern.compile(REG_IMAGES_REPLACE);
|
||||
PATTERN_LINKS = Pattern.compile(REG_LINKS);
|
||||
PATTERN_LINKS_REPLACE = Pattern.compile(REG_LINKS_REPLACE);
|
||||
}
|
||||
|
||||
public String parse(String pSource) {
|
||||
return unParseDolars(parseCode(parseHeaders(parseImages(parseLinks(parseBackSpaces(StringEscapeUtils.escapeHtml(parseDolars(pSource))))))));
|
||||
}
|
||||
|
||||
private String parseDolars(final String pSource) {
|
||||
return pSource.replace("$", "£ø");
|
||||
}
|
||||
|
||||
private String unParseDolars(final String pSource) {
|
||||
return pSource.replace("£ø", "$");
|
||||
}
|
||||
|
||||
protected String parseHeaders(final String pSource) {
|
||||
String result = pSource;
|
||||
for(int i = 1 ; i <= 3 ; i++) {
|
||||
result = parseHeadersHX(result, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String parseHeadersHX(final String pSource, final int pNumHeader) {
|
||||
String result = pSource;
|
||||
|
||||
// (.*)(\[hX\](.*)\[\/hX\])+(.*)
|
||||
final String regex = StringUtils.concat("(.*)(\\[h", pNumHeader, "\\](.*)\\[\\/h", pNumHeader, "\\])+(.*)");
|
||||
|
||||
final Pattern pattern = Pattern.compile(regex);
|
||||
|
||||
Matcher matcher = pattern.matcher(result);
|
||||
|
||||
while(matcher.find()) {
|
||||
// \1<hX>\3</hX>\4
|
||||
result = matcher.replaceFirst(StringUtils.concat(matcher.group(1),
|
||||
"<h", pNumHeader, ">", matcher.group(3), "</h", pNumHeader, ">", matcher.group(4)));
|
||||
matcher = pattern.matcher(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String parseBackSpaces(final String pSource) {
|
||||
return pSource.replaceAll("\r?\n", "<br/>").replaceAll("\\[\\/code\\]<br\\/><br\\/>", "[/code]\n");
|
||||
}
|
||||
|
||||
protected String parseImages(final String pSource) {
|
||||
String result = pSource;
|
||||
|
||||
Matcher matcher = PATTERN_IMAGES.matcher(result);
|
||||
|
||||
while(matcher.find()) {
|
||||
String altStr = matcher.group(3);
|
||||
|
||||
if(altStr == null) {
|
||||
altStr = "";
|
||||
}
|
||||
|
||||
result = matcher.replaceFirst(StringUtils.concat("<img src=\"", matcher.group(1), "\" alt=\"", altStr, "\" />"));
|
||||
matcher = PATTERN_IMAGES.matcher(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String parseLinks(final String pSource) {
|
||||
String result = pSource;
|
||||
|
||||
Matcher matcher = PATTERN_LINKS.matcher(result);
|
||||
|
||||
while(matcher.find()) {
|
||||
result = matcher.replaceFirst(StringUtils.concat("<a href=\"", matcher.group(1), "\">", matcher.group(2), "</a>"));
|
||||
matcher = PATTERN_LINKS.matcher(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String parseCode(final String pSource) {
|
||||
String result = pSource;
|
||||
|
||||
Matcher matcher = PATTERN_CODE.matcher(result);
|
||||
|
||||
while(matcher.find()) {
|
||||
// replace the '<br/>' in group by '\n'
|
||||
String codeContent = matcher.group(2).replaceAll("<br\\/>", "\n");
|
||||
if(codeContent.startsWith("\n")) {
|
||||
codeContent = codeContent.substring(1);
|
||||
}
|
||||
|
||||
result = matcher.replaceFirst(StringUtils.concat("<pre class=\"line-numbers\"><code class=\"language-", matcher.group(1), "\">", codeContent, "</code></pre>"));
|
||||
matcher = PATTERN_CODE.matcher(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package org.codiki.login;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.codiki.core.entities.dto.UserDAO;
|
||||
import org.codiki.core.entities.persistence.User;
|
||||
import org.codiki.core.repositories.UserRepository;
|
||||
import org.codiki.core.security.TokenService;
|
||||
import org.codiki.core.utils.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class LoginService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
/**
|
||||
* Check the user credentials and generate him a token if they are correct.
|
||||
*
|
||||
* @param pUser
|
||||
* The user sent from client.
|
||||
* @return The user populated with the generated token.
|
||||
* @throws AuthenticationException
|
||||
* If the credentials are wrong.
|
||||
*/
|
||||
public UserDAO checkCredentials(HttpServletResponse pResponse, UserDAO pUser) {
|
||||
UserDAO result = null;
|
||||
|
||||
Optional<User> user = userRepository.findByEmail(pUser.getEmail());
|
||||
|
||||
if(user.isPresent() && StringUtils.compareHash(pUser.getPassword(), user.get().getPassword())) {
|
||||
tokenService.addUser(user.get());
|
||||
result = new UserDAO(user.get());
|
||||
} else {
|
||||
pResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,23 @@
|
||||
package org.codiki.posts;
|
||||
|
||||
import java.util.List;
|
||||
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;
|
||||
import org.codiki.core.entities.persistence.Post;
|
||||
import org.codiki.core.repositories.PostRepository;
|
||||
import org.codiki.core.security.TokenService;
|
||||
import org.codiki.core.services.ParserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -11,11 +25,92 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/api/posts")
|
||||
public class PostController {
|
||||
|
||||
private static final int LIMIT_POSTS_HOME = 20;
|
||||
|
||||
@Autowired
|
||||
private ParserService parserService;
|
||||
|
||||
@Autowired
|
||||
private PostRepository postRepository;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@GetMapping
|
||||
public Iterable<Post> getAll() {
|
||||
return postRepository.findAll();
|
||||
public List<PostDTO> getAll() {
|
||||
return StreamSupport.stream(postRepository.findAll().spliterator(), false)
|
||||
.map(PostDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/{postKey}")
|
||||
public PostDTO getByKey(@PathVariable("postKey") final String pPostKey,
|
||||
final HttpServletResponse response) {
|
||||
PostDTO result = null;
|
||||
|
||||
final Optional<Post> post = postRepository.getByKey(pPostKey);
|
||||
if(post.isPresent()) {
|
||||
result = new PostDTO(post.get());
|
||||
result.setText(parserService.parse(result.getText()));
|
||||
} else {
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@GetMapping("/last")
|
||||
public List<PostDTO> getLast() {
|
||||
return postRepository.getLast(LIMIT_POSTS_HOME).stream()
|
||||
.map(PostDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PostMapping("/search")
|
||||
public List<Post> search() {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
@GetMapping("/byCategory/{categoryId}")
|
||||
public List<PostDTO> getByCategory(@PathVariable("categoryId") final Long pCategoryId) {
|
||||
return postRepository.getByCategoryId(pCategoryId).stream()
|
||||
.map(PostDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/myPosts")
|
||||
public List<PostDTO> getMyPosts(final HttpServletRequest pRequest, final HttpServletResponse pResponse) {
|
||||
return postRepository.getByCreator(tokenService
|
||||
.getAuthenticatedUserByToken(pRequest).getId())
|
||||
.parallelStream().map(PostDTO::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PostMapping("/preview")
|
||||
public PostDTO preview(@RequestBody final PostDTO pPost) {
|
||||
final PostDTO result = new PostDTO();
|
||||
|
||||
result.setTitle(pPost.getTitle());
|
||||
result.setImage(pPost.getImage() == null || "".equals(pPost.getImage())
|
||||
? "https://news-cdn.softpedia.com/images/news2/this-is-the-default-wallpaper-of-the-gnome-3-20-desktop-environment-500743-2.jpg"
|
||||
: pPost.getImage());
|
||||
result.setDescription(pPost.getDescription());
|
||||
result.setText(parserService.parse(pPost.getText()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@PostMapping("/")
|
||||
public PostDTO insert(@RequestBody final PostDTO pPost, final HttpServletRequest pRequest,
|
||||
final HttpServletResponse pResponse) {
|
||||
PostDTO result = null;
|
||||
|
||||
Optional<Post> postCreated = postService.insert(pPost, pRequest, pResponse);
|
||||
|
||||
if(postCreated.isPresent()) {
|
||||
result = new PostDTO(postCreated.get());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
41
src/main/java/org/codiki/posts/PostService.java
Normal file
41
src/main/java/org/codiki/posts/PostService.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package org.codiki.posts;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.codiki.core.entities.dto.PostDTO;
|
||||
import org.codiki.core.entities.persistence.Post;
|
||||
import org.codiki.core.repositories.PostRepository;
|
||||
import org.codiki.core.security.TokenService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class PostService {
|
||||
|
||||
@Autowired
|
||||
private PostRepository postRepository;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
public Optional<Post> insert(final PostDTO pPost, final HttpServletRequest pRequest,
|
||||
final HttpServletResponse pResponse) {
|
||||
Optional<Post> result = Optional.empty();
|
||||
|
||||
final String userToken = pRequest.getHeader("token");
|
||||
|
||||
if(userToken.equals(pPost.getAuthor().getToken())) {
|
||||
final Post postToSave = new Post(pPost);
|
||||
postToSave.setAuthor(tokenService.getAuthenticatedUserByToken(pRequest));
|
||||
postRepository.save(postToSave);
|
||||
result = Optional.of(postToSave);
|
||||
} else {
|
||||
pResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user