mirror of https://github.com/halo-dev/halo
Complete password update api and refactor user create api
parent
e8a9498ea4
commit
157689b0c2
|
@ -1,9 +1,10 @@
|
||||||
package cc.ryanc.halo.model.params;
|
package cc.ryanc.halo.model.params;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import javax.validation.constraints.Email;
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install parameters.
|
* Install parameters.
|
||||||
|
@ -11,8 +12,9 @@ import javax.validation.constraints.NotBlank;
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @date 3/19/19
|
* @date 3/19/19
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Data
|
@Data
|
||||||
public class InstallParam {
|
public class InstallParam extends UserParam {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blog locale.
|
* Blog locale.
|
||||||
|
@ -32,28 +34,10 @@ public class InstallParam {
|
||||||
@NotBlank(message = "Blog url must not be blank")
|
@NotBlank(message = "Blog url must not be blank")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
/**
|
|
||||||
* Username.
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "Username must not be blank")
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Nickname.
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "Nickname must not be blank")
|
|
||||||
private String nickname;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Email.
|
|
||||||
*/
|
|
||||||
@NotBlank(message = "Email must not be blank")
|
|
||||||
@Email(message = "It is not an email format")
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password.
|
* Password.
|
||||||
*/
|
*/
|
||||||
@NotBlank(message = "Password must not be blank")
|
@NotBlank(message = "Password must not be blank")
|
||||||
|
@Size(max = 100, message = "Length of password must not be more than {max}")
|
||||||
private String password;
|
private String password;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cc.ryanc.halo.model.params;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User password param.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PasswordParam {
|
||||||
|
|
||||||
|
@NotBlank(message = "Old password must not be blank")
|
||||||
|
@Size(max = 100, message = "Length of password must not be more than {max}")
|
||||||
|
private String oldPassword;
|
||||||
|
|
||||||
|
@NotBlank(message = "New password must not be blank")
|
||||||
|
@Size(max = 100, message = "Length of password must not be more than {max}")
|
||||||
|
private String newPassword;
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package cc.ryanc.halo.model.params;
|
||||||
import cc.ryanc.halo.model.dto.base.InputConverter;
|
import cc.ryanc.halo.model.dto.base.InputConverter;
|
||||||
import cc.ryanc.halo.model.entity.Tag;
|
import cc.ryanc.halo.model.entity.Tag;
|
||||||
import cc.ryanc.halo.utils.HaloUtils;
|
import cc.ryanc.halo.utils.HaloUtils;
|
||||||
import cn.hutool.core.util.URLUtil;
|
import cc.ryanc.halo.utils.SlugUtils;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public class TagParam implements InputConverter<Tag> {
|
||||||
public Tag convertTo() {
|
public Tag convertTo() {
|
||||||
if (StringUtils.isBlank(slugName)) {
|
if (StringUtils.isBlank(slugName)) {
|
||||||
// Handle slug name
|
// Handle slug name
|
||||||
slugName = URLUtil.normalize(name);
|
slugName = SlugUtils.slugify(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
slugName = HaloUtils.initializeUrlIfBlank(slugName);
|
slugName = HaloUtils.initializeUrlIfBlank(slugName);
|
||||||
|
|
|
@ -15,13 +15,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface TagService extends CrudService<Tag, Integer> {
|
public interface TagService extends CrudService<Tag, Integer> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove tag and relationship
|
|
||||||
*
|
|
||||||
* @param id id
|
|
||||||
*/
|
|
||||||
void remove(Integer id);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get tag by slug name
|
* Get tag by slug name
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cc.ryanc.halo.service;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.NotFoundException;
|
import cc.ryanc.halo.exception.NotFoundException;
|
||||||
import cc.ryanc.halo.model.entity.User;
|
import cc.ryanc.halo.model.entity.User;
|
||||||
|
import cc.ryanc.halo.model.params.UserParam;
|
||||||
import cc.ryanc.halo.service.base.CrudService;
|
import cc.ryanc.halo.service.base.CrudService;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
@ -73,4 +74,25 @@ public interface UserService extends CrudService<User, Integer> {
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
User login(@NonNull String key, @NonNull String password);
|
User login(@NonNull String key, @NonNull String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates user password.
|
||||||
|
*
|
||||||
|
* @param oldPassword old password must not be blank
|
||||||
|
* @param newPassword new password must not be blank
|
||||||
|
* @param userId user id must not be null
|
||||||
|
* @return updated user detail
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
User updatePassword(@NonNull String oldPassword, @NonNull String newPassword, @NonNull Integer userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an user.
|
||||||
|
*
|
||||||
|
* @param userParam user param must not be null.
|
||||||
|
* @param password password must not be blank
|
||||||
|
* @return created user
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
User createBy(@NonNull UserParam userParam, @NonNull String password);
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
@Override
|
@Override
|
||||||
public int getPostPageSize() {
|
public int getPostPageSize() {
|
||||||
try {
|
try {
|
||||||
return getByProperty(BlogProperties.INDEX_POSTS).map(Integer::valueOf).orElse(DEFAULT_POST_PAGE_SIZE);
|
return getByProperty(BlogProperties.INDEX_POSTS, Integer.class, DEFAULT_COMMENT_PAGE_SIZE);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
log.error(BlogProperties.INDEX_POSTS + " option is not a number format", e);
|
log.error(BlogProperties.INDEX_POSTS + " option is not a number format", e);
|
||||||
return DEFAULT_POST_PAGE_SIZE;
|
return DEFAULT_POST_PAGE_SIZE;
|
||||||
|
@ -202,7 +202,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
@Override
|
@Override
|
||||||
public int getCommentPageSize() {
|
public int getCommentPageSize() {
|
||||||
try {
|
try {
|
||||||
return getByProperty(BlogProperties.INDEX_COMMENTS).map(Integer::valueOf).orElse(DEFAULT_COMMENT_PAGE_SIZE);
|
return getByProperty(BlogProperties.INDEX_COMMENTS, Integer.class, DEFAULT_COMMENT_PAGE_SIZE);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
log.error(BlogProperties.INDEX_COMMENTS + " option is not a number format", e);
|
log.error(BlogProperties.INDEX_COMMENTS + " option is not a number format", e);
|
||||||
return DEFAULT_COMMENT_PAGE_SIZE;
|
return DEFAULT_COMMENT_PAGE_SIZE;
|
||||||
|
@ -212,7 +212,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
@Override
|
@Override
|
||||||
public int getRssPageSize() {
|
public int getRssPageSize() {
|
||||||
try {
|
try {
|
||||||
return getByProperty(BlogProperties.RSS_POSTS).map(Integer::valueOf).orElse(DEFAULT_RSS_PAGE_SIZE);
|
return getByProperty(BlogProperties.RSS_POSTS, Integer.class, DEFAULT_COMMENT_PAGE_SIZE);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
log.error(BlogProperties.RSS_POSTS + " setting is not a number format", e);
|
log.error(BlogProperties.RSS_POSTS + " setting is not a number format", e);
|
||||||
return DEFAULT_RSS_PAGE_SIZE;
|
return DEFAULT_RSS_PAGE_SIZE;
|
||||||
|
|
|
@ -32,16 +32,6 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
|
||||||
this.tagRepository = tagRepository;
|
this.tagRepository = tagRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove tag and relationship
|
|
||||||
*
|
|
||||||
* @param id id
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void remove(Integer id) {
|
|
||||||
// TODO 删除标签,以及对应的文章关系
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tag create(Tag tag) {
|
public Tag create(Tag tag) {
|
||||||
// Check if the tag is exist
|
// Check if the tag is exist
|
||||||
|
@ -73,6 +63,8 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
|
||||||
public List<TagOutputDTO> convertTo(List<Tag> tags) {
|
public List<TagOutputDTO> convertTo(List<Tag> tags) {
|
||||||
return CollectionUtils.isEmpty(tags) ?
|
return CollectionUtils.isEmpty(tags) ?
|
||||||
Collections.emptyList() :
|
Collections.emptyList() :
|
||||||
tags.stream().map(tag -> (TagOutputDTO) new TagOutputDTO().convertFrom(tag)).collect(Collectors.toList());
|
tags.stream()
|
||||||
|
.map(tag -> (TagOutputDTO) new TagOutputDTO().convertFrom(tag))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,14 @@ import cc.ryanc.halo.cache.StringCacheStore;
|
||||||
import cc.ryanc.halo.exception.BadRequestException;
|
import cc.ryanc.halo.exception.BadRequestException;
|
||||||
import cc.ryanc.halo.exception.NotFoundException;
|
import cc.ryanc.halo.exception.NotFoundException;
|
||||||
import cc.ryanc.halo.model.entity.User;
|
import cc.ryanc.halo.model.entity.User;
|
||||||
|
import cc.ryanc.halo.model.params.UserParam;
|
||||||
import cc.ryanc.halo.repository.UserRepository;
|
import cc.ryanc.halo.repository.UserRepository;
|
||||||
import cc.ryanc.halo.service.UserService;
|
import cc.ryanc.halo.service.UserService;
|
||||||
import cc.ryanc.halo.service.base.AbstractCrudService;
|
import cc.ryanc.halo.service.base.AbstractCrudService;
|
||||||
import cc.ryanc.halo.utils.DateUtils;
|
import cc.ryanc.halo.utils.DateUtils;
|
||||||
import cn.hutool.core.lang.Validator;
|
import cn.hutool.core.lang.Validator;
|
||||||
import cn.hutool.crypto.digest.BCrypt;
|
import cn.hutool.crypto.digest.BCrypt;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
||||||
if (!BCrypt.checkpw(password, user.getPassword())) {
|
if (!BCrypt.checkpw(password, user.getPassword())) {
|
||||||
// If the password is mismatched
|
// If the password is mismatched
|
||||||
// Add login failure count
|
// Add login failure count
|
||||||
Integer loginFailureCount = stringCacheStore.get(LOGIN_FAILURE_COUNT_KEY).map(countString -> Integer.valueOf(countString)).orElse(0);
|
Integer loginFailureCount = stringCacheStore.get(LOGIN_FAILURE_COUNT_KEY).map(Integer::valueOf).orElse(0);
|
||||||
|
|
||||||
if (loginFailureCount >= MAX_LOGIN_TRY) {
|
if (loginFailureCount >= MAX_LOGIN_TRY) {
|
||||||
// Set expiration
|
// Set expiration
|
||||||
|
@ -103,9 +105,53 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
||||||
throw new BadRequestException("账号或者密码错误,您还有" + (MAX_LOGIN_TRY - loginFailureCount) + "次机会");
|
throw new BadRequestException("账号或者密码错误,您还有" + (MAX_LOGIN_TRY - loginFailureCount) + "次机会");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Set session
|
// TODO Set session or cache token
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User updatePassword(String oldPassword, String newPassword, Integer userId) {
|
||||||
|
Assert.hasText(oldPassword, "Old password must not be blank");
|
||||||
|
Assert.hasText(newPassword, "New password must not be blank");
|
||||||
|
Assert.notNull(userId, "User id must not be blank");
|
||||||
|
|
||||||
|
if (oldPassword.equals(newPassword)) {
|
||||||
|
throw new BadRequestException("There is nothing changed because new password is equal to old password");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user
|
||||||
|
User user = getById(userId);
|
||||||
|
|
||||||
|
// Check the user old password
|
||||||
|
if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
|
||||||
|
throw new BadRequestException("Old password is mismatch").setErrorData(oldPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new password
|
||||||
|
setPassword(newPassword, user);
|
||||||
|
|
||||||
|
// Update this user
|
||||||
|
return update(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User createBy(UserParam userParam, String password) {
|
||||||
|
Assert.notNull(userParam, "User param must not be null");
|
||||||
|
Assert.hasText(password, "Password must not be blank");
|
||||||
|
|
||||||
|
User user = userParam.convertTo();
|
||||||
|
|
||||||
|
setPassword(password, user);
|
||||||
|
|
||||||
|
return create(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPassword(@NonNull String plainPassword, @NonNull User user) {
|
||||||
|
Assert.hasText(plainPassword, "Plain password must not be blank");
|
||||||
|
Assert.notNull(user, "User must not be null");
|
||||||
|
|
||||||
|
user.setPassword(BCrypt.hashpw(plainPassword, BCrypt.gensalt()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,9 @@ public class TagController {
|
||||||
@DeleteMapping("{tagId:\\d+}")
|
@DeleteMapping("{tagId:\\d+}")
|
||||||
@ApiOperation("Delete tag by id")
|
@ApiOperation("Delete tag by id")
|
||||||
public void deletePermanently(@PathVariable("tagId") Integer tagId) {
|
public void deletePermanently(@PathVariable("tagId") Integer tagId) {
|
||||||
|
// Remove the tag
|
||||||
tagService.removeById(tagId);
|
tagService.removeById(tagId);
|
||||||
|
// Remove the post tag relationship
|
||||||
postTagService.removeByTagId(tagId);
|
postTagService.removeByTagId(tagId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cc.ryanc.halo.web.controller.admin.api;
|
||||||
|
|
||||||
import cc.ryanc.halo.model.dto.UserOutputDTO;
|
import cc.ryanc.halo.model.dto.UserOutputDTO;
|
||||||
import cc.ryanc.halo.model.entity.User;
|
import cc.ryanc.halo.model.entity.User;
|
||||||
|
import cc.ryanc.halo.model.params.PasswordParam;
|
||||||
import cc.ryanc.halo.model.params.UserParam;
|
import cc.ryanc.halo.model.params.UserParam;
|
||||||
import cc.ryanc.halo.service.UserService;
|
import cc.ryanc.halo.service.UserService;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -35,4 +36,9 @@ public class UserController {
|
||||||
// Update user and convert to dto
|
// Update user and convert to dto
|
||||||
return new UserOutputDTO().convertFrom(userService.update(user));
|
return new UserOutputDTO().convertFrom(userService.update(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("profile/password")
|
||||||
|
public void updatePassword(@Valid @RequestBody PasswordParam passwordParam, User user) {
|
||||||
|
userService.updatePassword(passwordParam.getOldPassword(), passwordParam.getNewPassword(), user.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import cc.ryanc.halo.model.support.BaseResponse;
|
||||||
import cc.ryanc.halo.service.*;
|
import cc.ryanc.halo.service.*;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.crypto.digest.BCrypt;
|
|
||||||
import freemarker.template.Configuration;
|
import freemarker.template.Configuration;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -158,14 +157,7 @@ public class InstallController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private User createDefaultUser(InstallParam installParam) {
|
private User createDefaultUser(InstallParam installParam) {
|
||||||
User user = new User();
|
return userService.createBy(installParam, installParam.getPassword());
|
||||||
user.setUsername(installParam.getUsername());
|
|
||||||
user.setNickname(installParam.getNickname());
|
|
||||||
user.setEmail(installParam.getEmail());
|
|
||||||
// Hash password with BCrypt
|
|
||||||
user.setPassword(BCrypt.hashpw(installParam.getPassword(), BCrypt.gensalt()));
|
|
||||||
|
|
||||||
return userService.create(user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initSettings(InstallParam installParam) {
|
private void initSettings(InstallParam installParam) {
|
||||||
|
|
Loading…
Reference in New Issue