feat: 开发中...

This commit is contained in:
2023-03-28 19:52:22 +08:00
parent c92f52f67d
commit f9aa353fe9
20 changed files with 161 additions and 91 deletions

View File

@@ -20,12 +20,12 @@ public class BlogExceptionHandler {
private Environment environment; private Environment environment;
@ExceptionHandler(BadCredentialsException.class) @ExceptionHandler(BadCredentialsException.class)
public ResponseVO<String> onException(BadCredentialsException e) { public ResponseVO<String> onBadCredentialsException(BadCredentialsException e) {
return ResponseVO.failed(e.getMessage()); return ResponseVO.failed(e.getMessage());
} }
@ExceptionHandler(MethodArgumentNotValidException.class) @ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseVO<String> onException(MethodArgumentNotValidException e) { public ResponseVO<String> onMethodArgumentNotValidException(MethodArgumentNotValidException e) {
return ResponseVO.failed(e.getAllErrors() return ResponseVO.failed(e.getAllErrors()
.stream() .stream()
.findFirst() .findFirst()
@@ -36,8 +36,8 @@ public class BlogExceptionHandler {
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseVO<String> onException(Exception e) { public ResponseVO<String> onException(Exception e) {
log.error("", e);
if ("dev".equals(environment.getProperty("spring.profiles.active"))) { if ("dev".equals(environment.getProperty("spring.profiles.active"))) {
log.error("", e);
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer)); e.printStackTrace(new PrintWriter(writer));
// StringWriter 不需要 close() // StringWriter 不需要 close()

View File

@@ -1,6 +1,5 @@
package cn.hamster3.application.blog.config.security; package cn.hamster3.application.blog.config.security;
import cn.hamster3.application.blog.constant.UserPermissions;
import cn.hamster3.application.blog.dao.UserRepository; import cn.hamster3.application.blog.dao.UserRepository;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -9,6 +8,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Collections;
@Slf4j @Slf4j
@Component @Component
public class BlogUserDetailService implements UserDetailsService { public class BlogUserDetailService implements UserDetailsService {
@@ -22,10 +23,7 @@ public class BlogUserDetailService implements UserDetailsService {
.map(user -> new BlogUser( .map(user -> new BlogUser(
user.getEmail(), user.getEmail(),
user.getPassword(), user.getPassword(),
user.getPermissions() Collections.singleton(user.getRole().getAuthority()),
.stream()
.map(UserPermissions::getAuthority)
.toList(),
user.getId() user.getId()
)).orElseThrow(() -> new UsernameNotFoundException("user not found.")); )).orElseThrow(() -> new UsernameNotFoundException("user not found."));
} }

View File

@@ -2,12 +2,23 @@ package cn.hamster3.application.blog.constant;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
public enum UserPermissions { public enum UserRole {
MODIFY_USER_INFO, /**
MODIFY_USER_PERMISSION; * 读者
*/
USER,
/**
* 作者
*/
AUTHOR,
/**
* 管理员
*/
ADMIN;
private final SimpleGrantedAuthority authority; private final SimpleGrantedAuthority authority;
UserPermissions() { UserRole() {
this.authority = new SimpleGrantedAuthority(name()); this.authority = new SimpleGrantedAuthority(name());
} }

View File

@@ -1,12 +1,11 @@
package cn.hamster3.application.blog.controller; package cn.hamster3.application.blog.controller;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
/** @Tag(name = "附件接口", description = "附件相关接口")
* 附件相关接口
*/
@RestController @RestController
@RequestMapping("/api/v1/attach") @RequestMapping("/api/v1/attach")
public class AttachController { public class AttachController {

View File

@@ -4,6 +4,8 @@ import cn.hamster3.application.blog.service.IBlogService;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO; import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
import cn.hamster3.application.blog.vo.blog.BlogUpdateRequireVO; import cn.hamster3.application.blog.vo.blog.BlogUpdateRequireVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@@ -21,26 +23,34 @@ public class BlogController {
private IBlogService blogService; private IBlogService blogService;
@PostMapping("/") @PostMapping("/")
@Operation(summary = "创建博文")
public ResponseVO<Long> createBlog(@RequestBody @Valid BlogUpdateRequireVO requireVO) { public ResponseVO<Long> createBlog(@RequestBody @Valid BlogUpdateRequireVO requireVO) {
return blogService.createBlog(requireVO); return blogService.createBlog(requireVO);
} }
@GetMapping("/{blogID}/") @GetMapping("/{blogID}/")
@Operation(summary = "获取博文信息")
public ResponseVO<BlogInfoResponseVO> getBlogInfo(@PathVariable Long blogID) { public ResponseVO<BlogInfoResponseVO> getBlogInfo(@PathVariable Long blogID) {
return blogService.getBlogInfo(blogID); return blogService.getBlogInfo(blogID);
} }
@GetMapping("/") @GetMapping("/")
public ResponseVO<List<BlogInfoResponseVO>> getBlogInfoList(int page, int size) { @Operation(summary = "获取博文列表")
public ResponseVO<List<BlogInfoResponseVO>> getBlogInfoList(
@Parameter(description = "页码", example = "0") int page,
@Parameter(description = "大小", example = "10") int size
) {
return blogService.getBlogInfoList(PageRequest.of(page, size)); return blogService.getBlogInfoList(PageRequest.of(page, size));
} }
@PutMapping("/{blogID}/") @PutMapping("/{blogID}/")
@Operation(summary = "更新博文")
public ResponseVO<Void> updateBlog(@PathVariable Long blogID, @RequestBody @Valid BlogUpdateRequireVO requireVO) { public ResponseVO<Void> updateBlog(@PathVariable Long blogID, @RequestBody @Valid BlogUpdateRequireVO requireVO) {
return blogService.updateBlog(blogID, requireVO); return blogService.updateBlog(blogID, requireVO);
} }
@DeleteMapping("/{blogID}/") @DeleteMapping("/{blogID}/")
@Operation(summary = "删除博文")
public ResponseVO<Void> removeBlog(@PathVariable Long blogID) { public ResponseVO<Void> removeBlog(@PathVariable Long blogID) {
return blogService.removeBlog(blogID); return blogService.removeBlog(blogID);
} }

View File

@@ -1,20 +1,22 @@
package cn.hamster3.application.blog.controller; package cn.hamster3.application.blog.controller;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** @Tag(name = "网站设置接口", description = "网站设置相关接口")
* 网站设置相关接口
*/
@RestController @RestController
@RequestMapping(value = "/api/v1/settings", produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/api/v1/settings", produces = MediaType.APPLICATION_JSON_VALUE)
public class SiteSettingController { public class SiteSettingController {
@GetMapping("/{path}/") @GetMapping("/{path}/")
public ResponseVO<String> getSiteTitle(@PathVariable String path) { @Operation(summary = "获取网站设置")
public ResponseVO<String> getSiteSettings(@Parameter(description = "设置ID") @PathVariable String path) {
return ResponseVO.success(path); return ResponseVO.success(path);
} }

View File

@@ -1,60 +1,84 @@
package cn.hamster3.application.blog.controller; package cn.hamster3.application.blog.controller;
import cn.hamster3.application.blog.service.IUserService; import cn.hamster3.application.blog.service.IUserService;
import cn.hamster3.application.blog.vo.PageableResponseVO; import cn.hamster3.application.blog.vo.PageableVO;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
import cn.hamster3.application.blog.vo.user.*; import cn.hamster3.application.blog.vo.user.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.UUID; import java.util.UUID;
/** @Tag(name = "用户接口", description = "用户相关接口")
* 用户相关接口
*/
@RestController @RestController
@RequestMapping(value = "/api/v1/user", produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/api/v1/user", produces = MediaType.APPLICATION_JSON_VALUE)
public class UserController { public class UserController {
@Resource @Resource
private IUserService userService; private IUserService userService;
// @PostMapping("/login") @PostMapping("/login")
// public ResponseVO<Void> loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) { public ResponseVO<Void> loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) {
// return userService.loginUser(requireVO); return userService.loginUser(requireVO);
// } }
@GetMapping("/current") @GetMapping("/current")
@Operation(summary = "查询当前用户")
public ResponseVO<UserInfoResponseVO> getCurrentUserInfo() { public ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
return userService.getCurrentUserInfo(); return userService.getCurrentUserInfo();
} }
@PostMapping("/") @PostMapping("/")
@Operation(summary = "注册用户")
public ResponseVO<UserRegisterResponseVO> createUser(@RequestBody @Valid UserCreateRequireVO requireVO) { public ResponseVO<UserRegisterResponseVO> createUser(@RequestBody @Valid UserCreateRequireVO requireVO) {
return userService.createUser(requireVO); return userService.createUser(requireVO);
} }
@PutMapping("/") @PutMapping("/")
@Operation(summary = "更新用户信息")
public ResponseVO<Void> updateUser(@RequestBody @Valid UserUpdateRequireVO requireVO) { public ResponseVO<Void> updateUser(@RequestBody @Valid UserUpdateRequireVO requireVO) {
return userService.updateUser(requireVO); return userService.updateUser(requireVO);
} }
@GetMapping("/") @GetMapping("/")
public ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(int page, int size) { @Operation(summary = "查询用户列表")
public ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(
@Parameter(description = "页码", example = "0") int page,
@Parameter(description = "大小", example = "10") int size
) {
return userService.getAllUserInfo(PageRequest.of(page, size)); return userService.getAllUserInfo(PageRequest.of(page, size));
} }
@GetMapping("/{userID}/") @GetMapping("/{userID}/")
public ResponseVO<UserInfoResponseVO> getUserInfo(@PathVariable UUID userID) { @Operation(summary = "查询用户")
public ResponseVO<UserInfoResponseVO> getUserInfo(@Parameter(description = "用户ID") @PathVariable UUID userID) {
return userService.getUserInfo(userID); return userService.getUserInfo(userID);
} }
@GetMapping("/{userID}/attaches") @GetMapping("/{userID}/blog/")
public ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID) { @Operation(summary = "查询用户所有博文")
return userService.getUserAttaches(userID); public ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(
@Parameter(description = "用户ID") @PathVariable UUID userID,
@Parameter(description = "页码", example = "0") int page,
@Parameter(description = "大小", example = "10") int size
) {
return userService.getUserBlogList(userID, PageRequest.of(page, size));
}
@GetMapping("/{userID}/attach/")
@Operation(summary = "查询用户所有附件")
public ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(
@Parameter(description = "用户ID") @PathVariable UUID userID,
@Parameter(description = "页码", example = "0") int page,
@Parameter(description = "大小", example = "10") int size
) {
return userService.getUserAttachList(userID, PageRequest.of(page, size));
} }
} }

View File

@@ -1,8 +1,13 @@
package cn.hamster3.application.blog.dao; package cn.hamster3.application.blog.dao;
import cn.hamster3.application.blog.entity.AttachEntity; import cn.hamster3.application.blog.entity.AttachEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.UUID;
public interface AttachRepository extends JpaRepository<AttachEntity, Long>, JpaSpecificationExecutor<AttachEntity> { public interface AttachRepository extends JpaRepository<AttachEntity, Long>, JpaSpecificationExecutor<AttachEntity> {
Page<AttachEntity> findByUploader_IdOrderByCreateTimeDesc(UUID id, Pageable pageable);
} }

View File

@@ -1,12 +1,16 @@
package cn.hamster3.application.blog.dao; package cn.hamster3.application.blog.dao;
import cn.hamster3.application.blog.entity.BlogEntity; import cn.hamster3.application.blog.entity.BlogEntity;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.*; import org.springframework.data.jpa.repository.*;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
public interface BlogRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> { public interface BlogRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> {
Page<BlogEntity> findByUploader_IdOrderByAttachEntities_CreateTimeDesc(UUID id, Pageable pageable);
@EntityGraph(attributePaths = {"content"}) @EntityGraph(attributePaths = {"content"})
@Query("select b from BlogEntity b where b.id = ?1") @Query("select b from BlogEntity b where b.id = ?1")
Optional<BlogEntity> findByIDWithContent(Long id); Optional<BlogEntity> findByIDWithContent(Long id);

View File

@@ -2,8 +2,6 @@ package cn.hamster3.application.blog.dao;
import cn.hamster3.application.blog.entity.BlogEntity; import cn.hamster3.application.blog.entity.BlogEntity;
import cn.hamster3.application.blog.entity.UserEntity; import cn.hamster3.application.blog.entity.UserEntity;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -11,15 +9,10 @@ import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public interface UserRepository extends JpaRepository<UserEntity, UUID>, JpaSpecificationExecutor<BlogEntity> { public interface UserRepository extends JpaRepository<UserEntity, UUID>, JpaSpecificationExecutor<BlogEntity> {
@EntityGraph(attributePaths = {"permissions"})
Optional<UserEntity> findByEmailIgnoreCase(String email); Optional<UserEntity> findByEmailIgnoreCase(String email);
boolean existsByNicknameIgnoreCase(String nickname); boolean existsByNicknameIgnoreCase(String nickname);
boolean existsByEmailIgnoreCase(String email); boolean existsByEmailIgnoreCase(String email);
@EntityGraph(attributePaths = {"attachEntities"})
@NotNull
Optional<UserEntity> findById(@NotNull UUID uuid);
} }

View File

@@ -1,6 +1,6 @@
package cn.hamster3.application.blog.entity; package cn.hamster3.application.blog.entity;
import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.constant.UserRole;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -13,6 +13,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.util.*; import java.util.*;
@Getter @Getter
@Entity @Entity
@Table(name = "user_entity") @Table(name = "user_entity")
@@ -37,10 +38,9 @@ public class UserEntity {
private String password; private String password;
@Setter @Setter
@ElementCollection @Enumerated
@Column(name = "permission") @Column(name = "role", nullable = false)
@CollectionTable(name = "user_entity_permissions", joinColumns = @JoinColumn(name = "user_id")) private UserRole role;
private Set<UserPermissions> permissions = new HashSet<>();
@Setter @Setter
@OrderBy("create_time DESC") @OrderBy("create_time DESC")

View File

@@ -1,14 +1,13 @@
package cn.hamster3.application.blog.service; package cn.hamster3.application.blog.service;
import cn.hamster3.application.blog.vo.PageableResponseVO; import cn.hamster3.application.blog.vo.PageableVO;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
import cn.hamster3.application.blog.vo.user.*; import cn.hamster3.application.blog.vo.user.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface IUserService { public interface IUserService {
@@ -20,9 +19,11 @@ public interface IUserService {
@NotNull ResponseVO<Void> updateUser(@NotNull UserUpdateRequireVO requireVO); @NotNull ResponseVO<Void> updateUser(@NotNull UserUpdateRequireVO requireVO);
@NotNull ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable); @NotNull ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable);
@NotNull ResponseVO<UserInfoResponseVO> getUserInfo(UUID id); @NotNull ResponseVO<UserInfoResponseVO> getUserInfo(UUID id);
@NotNull ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID); @NotNull ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(@NotNull UUID userID, @NotNull Pageable pageable);
@NotNull ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(@NotNull UUID userID, @NotNull Pageable pageable);
} }

View File

@@ -34,7 +34,7 @@ public class BlogService implements IBlogService {
log.info("create blog vo: {}", requireVO); log.info("create blog vo: {}", requireVO);
UserEntity user = userAuditorAware.getCurrentAuditor().orElse(null); UserEntity user = userAuditorAware.getCurrentAuditor().orElse(null);
if (user == null) { if (user == null) {
return ResponseVO.failed("not login."); return ResponseVO.unauthorized();
} }
BlogEntity entity = blogMapper.voToEntity(requireVO); BlogEntity entity = blogMapper.voToEntity(requireVO);
entity = blogRepo.save(entity); entity = blogRepo.save(entity);
@@ -64,7 +64,7 @@ public class BlogService implements IBlogService {
} }
BlogUser user = UserAuditorAware.currentUser().orElse(null); BlogUser user = UserAuditorAware.currentUser().orElse(null);
if (user == null) { if (user == null) {
return ResponseVO.failed("not login."); return ResponseVO.unauthorized();
} }
//todo 权限检查 //todo 权限检查
blogRepo.updateTitleAndAbstractsAndPasswordAndContentById( blogRepo.updateTitleAndAbstractsAndPasswordAndContentById(

View File

@@ -1,16 +1,20 @@
package cn.hamster3.application.blog.service.impl; package cn.hamster3.application.blog.service.impl;
import cn.hamster3.application.blog.config.security.UserAuditorAware;
import cn.hamster3.application.blog.config.security.BlogUser; import cn.hamster3.application.blog.config.security.BlogUser;
import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.config.security.UserAuditorAware;
import cn.hamster3.application.blog.constant.UserRole;
import cn.hamster3.application.blog.dao.AttachRepository;
import cn.hamster3.application.blog.dao.BlogRepository;
import cn.hamster3.application.blog.dao.UserRepository; import cn.hamster3.application.blog.dao.UserRepository;
import cn.hamster3.application.blog.entity.UserEntity; import cn.hamster3.application.blog.entity.UserEntity;
import cn.hamster3.application.blog.entity.mapper.AttachMapper; import cn.hamster3.application.blog.entity.mapper.AttachMapper;
import cn.hamster3.application.blog.entity.mapper.BlogMapper;
import cn.hamster3.application.blog.entity.mapper.UserMapper; import cn.hamster3.application.blog.entity.mapper.UserMapper;
import cn.hamster3.application.blog.service.IUserService; import cn.hamster3.application.blog.service.IUserService;
import cn.hamster3.application.blog.vo.PageableResponseVO; import cn.hamster3.application.blog.vo.PageableVO;
import cn.hamster3.application.blog.vo.ResponseVO; import cn.hamster3.application.blog.vo.ResponseVO;
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO; import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
import cn.hamster3.application.blog.vo.user.*; import cn.hamster3.application.blog.vo.user.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -20,9 +24,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Slf4j @Slf4j
@@ -34,10 +36,16 @@ public class UserService implements IUserService {
@Resource @Resource
private UserMapper userMapper; private UserMapper userMapper;
@Resource @Resource
private BlogMapper blogMapper;
@Resource
private AttachMapper attachMapper; private AttachMapper attachMapper;
@Resource @Resource
private UserRepository userRepo; private UserRepository userRepo;
@Resource
private BlogRepository blogRepo;
@Resource
private AttachRepository attachRepo;
@Override @Override
public @NotNull ResponseVO<Void> loginUser(@NotNull UserLoginRequireVO requireVO) { public @NotNull ResponseVO<Void> loginUser(@NotNull UserLoginRequireVO requireVO) {
@@ -48,7 +56,7 @@ public class UserService implements IUserService {
public @NotNull ResponseVO<UserInfoResponseVO> getCurrentUserInfo() { public @NotNull ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
UUID uuid = UserAuditorAware.currentUserUUID().orElse(null); UUID uuid = UserAuditorAware.currentUserUUID().orElse(null);
if (uuid == null) { if (uuid == null) {
return ResponseVO.failed("not login."); return ResponseVO.unauthorized();
} }
return ResponseVO.success( return ResponseVO.success(
userRepo.findById(uuid) userRepo.findById(uuid)
@@ -71,6 +79,7 @@ public class UserService implements IUserService {
} }
entity.setPassword(passwordEncoder.encode(entity.getPassword())); entity.setPassword(passwordEncoder.encode(entity.getPassword()));
entity.setRole(UserRole.USER);
log.info("prepare to save userinfo: {}", entity); log.info("prepare to save userinfo: {}", entity);
UserEntity save = userRepo.save(entity); UserEntity save = userRepo.save(entity);
@@ -91,7 +100,7 @@ public class UserService implements IUserService {
return ResponseVO.failed("你没有这个权限!"); return ResponseVO.failed("你没有这个权限!");
} }
if (!blogUser.getId().equals(userEntity.getId()) if (!blogUser.getId().equals(userEntity.getId())
&& blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_INFO.getAuthority())) { && !blogUser.getAuthorities().contains(UserRole.ADMIN.getAuthority())) {
return ResponseVO.failed("你没有这个权限!"); return ResponseVO.failed("你没有这个权限!");
} }
if (requireVO.getEmail() != null && !requireVO.getEmail().equals(userEntity.getEmail())) { if (requireVO.getEmail() != null && !requireVO.getEmail().equals(userEntity.getEmail())) {
@@ -110,22 +119,23 @@ public class UserService implements IUserService {
userEntity.setPassword(passwordEncoder.encode(requireVO.getPassword())); userEntity.setPassword(passwordEncoder.encode(requireVO.getPassword()));
} }
if (requireVO.getPermissions() != null) { if (requireVO.getRole() != null) {
if (!blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_PERMISSION.getAuthority())) {
return ResponseVO.failed("你没有这个权限!");
}
// 用户必须具有 MODIFY_USER_PERMISSION 权限,且操作对象不为用户自己时才能更改权限
if (blogUser.getId().equals(userEntity.getId())) { if (blogUser.getId().equals(userEntity.getId())) {
return ResponseVO.failed("你不能更改自己的权限!"); return ResponseVO.failed("你不能更改自己的权限!");
} }
userEntity.setPermissions(requireVO.getPermissions()); if (!blogUser.getAuthorities().contains(UserRole.ADMIN.getAuthority())) {
return ResponseVO.failed("你没有这个权限!");
}
// 用户必须具有 ADMIN 权限,且操作对象不为用户自己时才能更改权限
userEntity.setRole(requireVO.getRole());
} }
userRepo.save(userEntity);
return ResponseVO.success(); return ResponseVO.success();
} }
@Override @Override
public @NotNull ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable) { public @NotNull ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable) {
return PageableResponseVO.success( return PageableVO.success(
userRepo.findAll(pageable).map(o -> userMapper.entityToInfoVO(o)) userRepo.findAll(pageable).map(o -> userMapper.entityToInfoVO(o))
); );
} }
@@ -138,14 +148,18 @@ public class UserService implements IUserService {
} }
@Override @Override
public @NotNull ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID) { public @NotNull ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(@NotNull UUID userID, @NotNull Pageable pageable) {
UserEntity userEntity = userRepo.findById(userID).orElse(null); return PageableVO.success(
if (userEntity == null) { blogRepo.findByUploader_IdOrderByAttachEntities_CreateTimeDesc(userID, pageable)
return ResponseVO.failed("未找到该用户!"); .map(o -> blogMapper.entityToInfoVO(o))
} );
List<AttachInfoResponseVO> list = userEntity.getAttachEntities() }
.stream().map(o -> attachMapper.entityToInfoVO(o))
.toList(); @Override
return ResponseVO.success(list); public @NotNull ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(@NotNull UUID userID, @NotNull Pageable pageable) {
return PageableVO.success(
attachRepo.findByUploader_IdOrderByCreateTimeDesc(userID, pageable)
.map(o -> attachMapper.entityToInfoVO(o))
);
} }
} }

View File

@@ -8,19 +8,19 @@ import java.util.List;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class PageableResponseVO<T> { public class PageableVO<T> {
private int page; private int page;
private int size; private int size;
private long totalElements; private long totalElements;
private int totalPage; private int totalPage;
private List<T> data; private List<T> data;
public static <T> ResponseVO<PageableResponseVO<T>> success(Page<T> page) { public static <T> ResponseVO<PageableVO<T>> success(Page<T> page) {
return ResponseVO.success(of(page)); return ResponseVO.success(of(page));
} }
public static <T> PageableResponseVO<T> of(Page<T> page) { public static <T> PageableVO<T> of(Page<T> page) {
return new PageableResponseVO<>( return new PageableVO<>(
page.getNumber(), page.getNumber(),
page.getSize(), page.getSize(),
page.getTotalElements(), page.getTotalElements(),

View File

@@ -27,7 +27,11 @@ public class ResponseVO<T> {
return new ResponseVO<>(200, msg, data); return new ResponseVO<>(200, msg, data);
} }
public static <T> ResponseVO<T> failed(String msg) { public static <T> ResponseVO<T> unauthorized() {
return new ResponseVO<>(401, "Unauthorized", null);
}
public static <T> ResponseVO<T> failed(@NotNull String msg) {
return new ResponseVO<>(403, msg, null); return new ResponseVO<>(403, msg, null);
} }

View File

@@ -1,5 +1,6 @@
package cn.hamster3.application.blog.vo.user; package cn.hamster3.application.blog.vo.user;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -8,10 +9,13 @@ import lombok.Data;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class UserCreateRequireVO { public class UserCreateRequireVO {
@Parameter(name = "邮箱")
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!") @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
private String email; private String email;
@Parameter(name = "昵称")
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!") @Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
private String nickname; private String nickname;
@Parameter(name = "密码")
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
private String password; private String password;
} }

View File

@@ -1,10 +1,9 @@
package cn.hamster3.application.blog.vo.user; package cn.hamster3.application.blog.vo.user;
import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.constant.UserRole;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
@Data @Data
@@ -13,5 +12,5 @@ public class UserInfoResponseVO {
private UUID id; private UUID id;
private String email; private String email;
private String nickname; private String nickname;
private Set<UserPermissions> permissions; private UserRole role;
} }

View File

@@ -1,11 +1,9 @@
package cn.hamster3.application.blog.vo.user; package cn.hamster3.application.blog.vo.user;
import cn.hamster3.application.blog.constant.UserPermissions;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Data @Data
@@ -14,7 +12,6 @@ public class UserRegisterResponseVO {
private UUID id; private UUID id;
private String email; private String email;
private String nickname; private String nickname;
private List<UserPermissions> permissions;
private Date createTime; private Date createTime;
private Date updateTime; private Date updateTime;
} }

View File

@@ -1,23 +1,28 @@
package cn.hamster3.application.blog.vo.user; package cn.hamster3.application.blog.vo.user;
import cn.hamster3.application.blog.constant.UserPermissions; import cn.hamster3.application.blog.constant.UserRole;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import lombok.Data; import lombok.Data;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
@Data @Data
public class UserUpdateRequireVO { public class UserUpdateRequireVO {
@Parameter(name = "用户ID")
@NotNull(message = "用户id不能为空") @NotNull(message = "用户id不能为空")
private UUID id; private UUID id;
@Parameter(name = "邮箱")
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!") @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
private String email; private String email;
@Parameter(name = "昵称")
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!") @Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
private String nickname; private String nickname;
@Parameter(name = "密码")
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
private String password; private String password;
private Set<UserPermissions> permissions; @Parameter(name = "角色")
private UserRole role;
} }