ソースを参照

feat: 增加重设密码,删除课程、幻灯片(伪删除)功能

ChenSiTong 6 年 前
コミット
b61d4811d4
26 ファイル変更299 行追加98 行削除
  1. 2 2
      src/main/java/nju/seec/helper/controller/ControllerAdvice.java
  2. 11 0
      src/main/java/nju/seec/helper/controller/CourseController.java
  3. 12 0
      src/main/java/nju/seec/helper/controller/SlideController.java
  4. 12 2
      src/main/java/nju/seec/helper/controller/UserController.java
  5. 22 5
      src/main/java/nju/seec/helper/dao/CourseDAO.java
  6. 15 0
      src/main/java/nju/seec/helper/dao/SlideDAO.java
  7. 8 0
      src/main/java/nju/seec/helper/dao/UserDAO.java
  8. 0 2
      src/main/java/nju/seec/helper/dto/CourseDTO.java
  9. 3 0
      src/main/java/nju/seec/helper/dto/LoginDTO.java
  10. 27 0
      src/main/java/nju/seec/helper/dto/ResetPasswordDTO.java
  11. 0 3
      src/main/java/nju/seec/helper/dto/modify/ModifyUserDTO.java
  12. 7 3
      src/main/java/nju/seec/helper/entity/Course.java
  13. 3 0
      src/main/java/nju/seec/helper/entity/Slide.java
  14. 17 0
      src/main/java/nju/seec/helper/service/AuthUtil.java
  15. 15 7
      src/main/java/nju/seec/helper/service/CourseService.java
  16. 2 1
      src/main/java/nju/seec/helper/service/ReplyService.java
  17. 14 0
      src/main/java/nju/seec/helper/service/SlideService.java
  18. 17 9
      src/main/java/nju/seec/helper/service/UserService.java
  19. 6 10
      src/main/java/nju/seec/helper/service/impl/CommentServiceImpl.java
  20. 35 16
      src/main/java/nju/seec/helper/service/impl/CourseServiceImpl.java
  21. 3 6
      src/main/java/nju/seec/helper/service/impl/ReplyServiceImpl.java
  22. 20 12
      src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java
  23. 38 14
      src/main/java/nju/seec/helper/service/impl/UserServiceImpl.java
  24. 6 0
      src/main/java/nju/seec/helper/util/EncryptUtils.java
  25. 0 2
      src/main/java/nju/seec/helper/vo/CourseVO.java
  26. 4 4
      src/main/resources/application-dev.yml

+ 2 - 2
src/main/java/nju/seec/helper/controller/ControllerAdvice.java

@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
 public class ControllerAdvice {
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
-        return ErrorResponse.of(400, ex.getBindingResult().toString());
+        return ErrorResponse.of(400, "请检查您输入的数据");
     }
 
     @ExceptionHandler(HelperException.class)
@@ -26,6 +26,6 @@ public class ControllerAdvice {
     @ExceptionHandler(Exception.class)
     public ErrorResponse handleException(Exception e) {
         log.error(e.getLocalizedMessage());
-        return ErrorResponse.of(500, e.getLocalizedMessage());
+        return ErrorResponse.of(500, "系统异常,请重试");
     }
 }

+ 11 - 0
src/main/java/nju/seec/helper/controller/CourseController.java

@@ -43,6 +43,17 @@ public class CourseController {
         return ResourceResponse.of(courseVO);
     }
 
+    /**
+     * 教师删除课程(伪删除)
+     */
+    @Auth(roles = UserType.TEACHER, message = "删除课程")
+    @DeleteMapping("/{courseId}")
+    public EmptyResponse removeCourse(LoginUser user,
+                                      @PathVariable Integer courseId) {
+        courseService.removeCourse(user, courseId);
+        return EmptyResponse.getInstance();
+    }
+
     /**
      * 教师修改课程
      */

+ 12 - 0
src/main/java/nju/seec/helper/controller/SlideController.java

@@ -1,6 +1,7 @@
 package nju.seec.helper.controller;
 
 import nju.seec.helper.aspect.auth.Auth;
+import nju.seec.helper.controller.response.EmptyResponse;
 import nju.seec.helper.controller.response.PageResourceResponse;
 import nju.seec.helper.controller.response.ResourceResponse;
 import nju.seec.helper.dto.LoginUser;
@@ -52,6 +53,17 @@ public class SlideController {
         return ResourceResponse.of(slideVO);
     }
 
+    /**
+     * 教师删除幻灯片
+     */
+    @Auth(roles = UserType.TEACHER, message = "删除幻灯片")
+    @DeleteMapping("/{slideId}")
+    public EmptyResponse removeSlide(LoginUser user,
+                                     @PathVariable Integer slideId) {
+        slideService.removeSlide(user, slideId);
+        return EmptyResponse.getInstance();
+    }
+
     /**
      * 教师获取幻灯片
      */

+ 12 - 2
src/main/java/nju/seec/helper/controller/UserController.java

@@ -6,6 +6,7 @@ import nju.seec.helper.controller.response.ResourceResponse;
 import nju.seec.helper.dto.LoginDTO;
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.dto.ResetPasswordDTO;
 import nju.seec.helper.dto.modify.ModifyUserDTO;
 import nju.seec.helper.service.UserService;
 import nju.seec.helper.util.Consts;
@@ -43,8 +44,8 @@ public class UserController {
      * 邮箱登录
      */
     @PostMapping("/login/email")
-    public ResourceResponse<UserVO> emailLogin(@Valid @RequestBody LoginDTO loginDTO,
-                                               HttpSession session) {
+    public ResourceResponse<UserVO> loginByEmail(@Valid @RequestBody LoginDTO loginDTO,
+                                                 HttpSession session) {
         UserVO userVO = userService.getUserByEmailAndPassword(loginDTO.getUsername(), loginDTO.getPassword());
 
         LoginUser user = new LoginUser()
@@ -85,6 +86,15 @@ public class UserController {
         return ResourceResponse.of(userVO);
     }
 
+    /**
+     * 重设密码
+     */
+    @PutMapping("/resetPassword/email")
+    public EmptyResponse resetPasswordByEmail(@Valid @RequestBody ResetPasswordDTO resetPasswordDTO) {
+        userService.resetPasswordByEmail(resetPasswordDTO);
+        return EmptyResponse.getInstance();
+    }
+
     /**
      * 获取个人信息
      */

+ 22 - 5
src/main/java/nju/seec/helper/dao/CourseDAO.java

@@ -5,6 +5,7 @@ import nju.seec.helper.util.exception.HelperException;
 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.Query;
 import org.springframework.stereotype.Repository;
 
 import java.util.Set;
@@ -28,11 +29,16 @@ public interface CourseDAO extends JpaRepository<Course, Integer> {
     /**
      * 检查老师是否已创建同名课程
      *
-     * @param name
      * @param teacherId
+     * @param name
      * @return
      */
-    boolean existsByNameAndTeacherId(String name, Integer teacherId);
+    @Query("select case when count(c.id)>0 then true else false end " +
+            "from Course c " +
+            "where c.teacherId=?1 " +
+            "and c.name=?2 " +
+            "and c.deleteAt=0")
+    boolean existsByTeacherIdAndName(Integer teacherId, String name);
 
     /**
      * 查询老师创建的课程
@@ -42,7 +48,11 @@ public interface CourseDAO extends JpaRepository<Course, Integer> {
      * @param pageable
      * @return
      */
-    Page<Course> findByTeacherIdAndNameContains(Integer teacherId, String key, Pageable pageable);
+    @Query("select c from Course c " +
+            "where c.teacherId=?1 " +
+            "and c.name like concat('%',?2,'%') " +
+            "and c.deleteAt=0 ")
+    Page<Course> findByTeacherIdAndKey(Integer teacherId, String key, Pageable pageable);
 
     /**
      * 查询课程
@@ -51,7 +61,10 @@ public interface CourseDAO extends JpaRepository<Course, Integer> {
      * @param pageable
      * @return
      */
-    Page<Course> findByNameContains(String key, Pageable pageable);
+    @Query("select c from Course c " +
+            "where (c.name like concat('%',?1,'%') or c.teacherName like concat('%',?1,'%')) " +
+            "and c.deleteAt=0 ")
+    Page<Course> findByKey(String key, Pageable pageable);
 
     /**
      * 按ID列表查询
@@ -61,5 +74,9 @@ public interface CourseDAO extends JpaRepository<Course, Integer> {
      * @param pageable
      * @return
      */
-    Page<Course> findByIdInAndNameContains(Set<Integer> courseIds, String key, Pageable pageable);
+    @Query("select c from Course c " +
+            "where c.id in ?1 " +
+            "and (c.name like concat('%',?2,'%') or c.teacherName like concat('%',?2,'%')) " +
+            "and c.deleteAt=0 ")
+    Page<Course> findByIdsAndKey(Set<Integer> courseIds, String key, Pageable pageable);
 }

+ 15 - 0
src/main/java/nju/seec/helper/dao/SlideDAO.java

@@ -6,6 +6,7 @@ import nju.seec.helper.util.exception.HelperException;
 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.Query;
 import org.springframework.stereotype.Repository;
 
 import java.util.Set;
@@ -34,6 +35,10 @@ public interface SlideDAO extends JpaRepository<Slide, Integer> {
      * @param pageable
      * @return
      */
+    @Query("select s from Slide s " +
+            "where s.teacherId=?1 " +
+            "and s.name like concat('%',?2,'%') " +
+            "and s.deleteAt=0")
     Page<Slide> findByTeacherIdAndNameContains(Integer teacherId, String key, Pageable pageable);
 
     /**
@@ -45,6 +50,11 @@ public interface SlideDAO extends JpaRepository<Slide, Integer> {
      * @param pageable
      * @return
      */
+    @Query("select s from Slide s " +
+            "where s.courseId=?1 " +
+            "and s.teacherId=?2 " +
+            "and s.name like concat('%',?3,'%') " +
+            "and s.deleteAt=0")
     Page<Slide> findByCourseIdAndTeacherIdAndNameContains(Integer courseId, Integer teacherId, String key, Pageable pageable);
 
     /**
@@ -56,5 +66,10 @@ public interface SlideDAO extends JpaRepository<Slide, Integer> {
      * @param pageable
      * @return
      */
+    @Query("select s from Slide s " +
+            "where s.courseId=?1 " +
+            "and s.state not in ?2" +
+            "and s.name like concat('%',?3,'%') " +
+            "and s.deleteAt=0")
     Page<Slide> findByCourseIdAndStateNotInAndNameContains(Integer courseId, Set<SlideState> exclusiveStates, String key, Pageable pageable);
 }

+ 8 - 0
src/main/java/nju/seec/helper/dao/UserDAO.java

@@ -48,4 +48,12 @@ public interface UserDAO extends JpaRepository<User, Integer> {
      * @return
      */
     Optional<User> findByEmailAndPassword(String email, String password);
+
+    /**
+     * 根据邮箱查询
+     *
+     * @param email
+     * @return
+     */
+    Optional<User> findByEmail(String email);
 }

+ 0 - 2
src/main/java/nju/seec/helper/dto/CourseDTO.java

@@ -16,6 +16,4 @@ public class CourseDTO {
     private String bio;
     @NotBlank
     private String code;
-
-    private String cover;
 }

+ 3 - 0
src/main/java/nju/seec/helper/dto/LoginDTO.java

@@ -9,6 +9,9 @@ import javax.validation.constraints.NotBlank;
  */
 @Data
 public class LoginDTO {
+    /**
+     * 邮箱或手机号
+     */
     @NotBlank
     private String username;
     @NotBlank

+ 27 - 0
src/main/java/nju/seec/helper/dto/ResetPasswordDTO.java

@@ -0,0 +1,27 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * @author cst
+ */
+@Data
+public class ResetPasswordDTO {
+    /**
+     * 邮箱或手机号
+     */
+    @NotBlank
+    private String username;
+    /**
+     * 验证码
+     */
+    @NotBlank
+    private String code;
+    /**
+     * 密码
+     */
+    @NotBlank
+    private String password;
+}

+ 0 - 3
src/main/java/nju/seec/helper/dto/modify/ModifyUserDTO.java

@@ -13,7 +13,4 @@ public class ModifyUserDTO {
     @NotBlank
     @Length(min = 2)
     private String name;
-
-    @NotBlank
-    private String password;
 }

+ 7 - 3
src/main/java/nju/seec/helper/entity/Course.java

@@ -3,6 +3,7 @@ package nju.seec.helper.entity;
 import lombok.Data;
 import lombok.experimental.Accessors;
 import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.DynamicUpdate;
 
 import javax.persistence.*;
 import java.time.LocalDateTime;
@@ -13,7 +14,9 @@ import java.time.LocalDateTime;
 @Data
 @Accessors(chain = true)
 @Entity
-@Table(name = "course")
+@Table(name = "course",
+        uniqueConstraints = @UniqueConstraint(name = "课程名唯一约束", columnNames = {"teacher_id", "name", "delete_at"}))
+@DynamicUpdate
 public class Course {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -28,8 +31,6 @@ public class Course {
     @Column(nullable = false)
     private String code;
 
-    private String cover;
-
     @Column(name = "create_at", nullable = false, updatable = false)
     @CreationTimestamp
     private LocalDateTime createAt;
@@ -42,4 +43,7 @@ public class Course {
      */
     @Column(name = "teacher_name", nullable = false)
     private String teacherName;
+
+    @Column(name = "delete_at", columnDefinition = "bigint default 0 not null")
+    private Long deleteAt = 0L;
 }

+ 3 - 0
src/main/java/nju/seec/helper/entity/Slide.java

@@ -47,4 +47,7 @@ public class Slide {
 
     @Column(nullable = false)
     private Integer pages;
+
+    @Column(name = "delete_at", columnDefinition = "bigint default 0 not null")
+    private Long deleteAt = 0L;
 }

+ 17 - 0
src/main/java/nju/seec/helper/service/AuthUtil.java

@@ -0,0 +1,17 @@
+package nju.seec.helper.service;
+
+import lombok.NonNull;
+import lombok.experimental.UtilityClass;
+import nju.seec.helper.util.exception.HelperException;
+
+/**
+ * @author cst
+ */
+@UtilityClass
+public class AuthUtil {
+    public void checkDataAuth(@NonNull Integer userId, @NonNull Integer dateUserId, String errMsg) {
+        if (!userId.equals(dateUserId)) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, errMsg);
+        }
+    }
+}

+ 15 - 7
src/main/java/nju/seec/helper/service/CourseService.java

@@ -25,11 +25,19 @@ public interface CourseService {
     /**
      * 修改课程
      *
-     * @param teacher
+     * @param user
      * @param modifyCourseDTO
      * @return
      */
-    CourseVO modifyCourse(LoginUser teacher, ModifyCourseDTO modifyCourseDTO);
+    CourseVO modifyCourse(LoginUser user, ModifyCourseDTO modifyCourseDTO);
+
+    /**
+     * 删除课程(伪删除)
+     *
+     * @param user
+     * @param courseId
+     */
+    void removeCourse(LoginUser user, Integer courseId);
 
     /**
      * 学生选课
@@ -40,23 +48,23 @@ public interface CourseService {
     void chooseCourse(LoginUser student, ChooseDTO chooseDTO);
 
     /**
-     * 教师获取创建课程
+     * 获取课程
      *
-     * @param teacher
      * @param key
      * @param pageable
      * @return
      */
-    List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable);
+    List<CourseVO> getCourses(String key, Pageable pageable);
 
     /**
-     * 获取课程
+     * 教师获取创建课程
      *
+     * @param teacher
      * @param key
      * @param pageable
      * @return
      */
-    List<CourseVO> getCourses(String key, Pageable pageable);
+    List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable);
 
     /**
      * 学生获取已选课程

+ 2 - 1
src/main/java/nju/seec/helper/service/ReplyService.java

@@ -10,7 +10,8 @@ import nju.seec.helper.vo.ReplyVO;
 public interface ReplyService {
     /**
      * 创建回复
-     *  @param user
+     *
+     * @param user
      * @param replyDTO
      * @return
      */

+ 14 - 0
src/main/java/nju/seec/helper/service/SlideService.java

@@ -30,6 +30,14 @@ public interface SlideService {
      */
     SlideVO modifySlide(LoginUser user, ModifySlideDTO modifySlideDTO);
 
+    /**
+     * 删除幻灯片(伪删除)
+     *
+     * @param user
+     * @param slideId
+     */
+    void removeSlide(LoginUser user, Integer slideId);
+
     /**
      * 教师获取幻灯片
      *
@@ -42,6 +50,12 @@ public interface SlideService {
 
     /**
      * 教师基于课程获取幻灯片
+     *
+     * @param teacher
+     * @param courseId
+     * @param key
+     * @param pageable
+     * @return
      */
     List<SlideVO> teacherGetSlidesByCourse(LoginUser teacher, Integer courseId, String key, Pageable pageable);
 

+ 17 - 9
src/main/java/nju/seec/helper/service/UserService.java

@@ -2,6 +2,7 @@ package nju.seec.helper.service;
 
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.dto.ResetPasswordDTO;
 import nju.seec.helper.dto.modify.ModifyUserDTO;
 import nju.seec.helper.vo.UserVO;
 
@@ -17,6 +18,22 @@ public interface UserService {
      */
     UserVO createUser(RegisterDTO registerDTO);
 
+    /**
+     * 修改用户信息
+     *
+     * @param loginUser
+     * @param modifyUserDTO
+     * @return
+     */
+    UserVO modifyUser(LoginUser loginUser, ModifyUserDTO modifyUserDTO);
+
+    /**
+     * 重设密码
+     *
+     * @param resetPasswordDTO
+     */
+    void resetPasswordByEmail(ResetPasswordDTO resetPasswordDTO);
+
     /**
      * 根据邮箱和密码匹配用户
      *
@@ -33,13 +50,4 @@ public interface UserService {
      * @return
      */
     UserVO getUserById(Integer userId);
-
-    /**
-     * 修改用户信息
-     *
-     * @param loginUser
-     * @param modifyUserDTO
-     * @return
-     */
-    UserVO modifyUser(LoginUser loginUser, ModifyUserDTO modifyUserDTO);
 }

+ 6 - 10
src/main/java/nju/seec/helper/service/impl/CommentServiceImpl.java

@@ -5,8 +5,8 @@ import nju.seec.helper.dao.SlideDAO;
 import nju.seec.helper.dto.CommentDTO;
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.entity.Comment;
+import nju.seec.helper.service.AuthUtil;
 import nju.seec.helper.service.CommentService;
-import nju.seec.helper.util.exception.HelperException;
 import nju.seec.helper.vo.CommentVO;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
@@ -47,9 +47,9 @@ public class CommentServiceImpl implements CommentService {
     @Override
     public void removeComment(LoginUser user, Integer commentId) {
         Comment comment = commentDAO.findCommentById(commentId);
-        if (!comment.getUserId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权删除该评论");
-        }
+
+        AuthUtil.checkDataAuth(user.getId(), comment.getUserId(), "您无权删除该评论");
+
         unTopComment(comment);
         commentDAO.delete(comment);
     }
@@ -59,9 +59,7 @@ public class CommentServiceImpl implements CommentService {
     public void topComment(LoginUser user, Integer commentId) {
         Comment comment = commentDAO.findCommentById(commentId);
 
-        if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权在该评论区置顶评论");
-        }
+        AuthUtil.checkDataAuth(user.getId(), slideDAO.findSlideById(comment.getSlideId()).getTeacherId(), "您无权在该评论区置顶评论");
 
         unTopComment(comment);
         comment.setTopNumber(commentDAO.countTopComments(comment.getSlideId(), comment.getPageNumber()) + 1);
@@ -73,9 +71,7 @@ public class CommentServiceImpl implements CommentService {
     public void unTopComment(LoginUser user, Integer commentId) {
         Comment comment = commentDAO.findCommentById(commentId);
 
-        if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权在该评论区取消置顶评论");
-        }
+        AuthUtil.checkDataAuth(user.getId(), slideDAO.findSlideById(comment.getSlideId()).getTeacherId(), "您无权在该评论区取消置顶评论");
 
         unTopComment(comment);
         commentDAO.save(comment);

+ 35 - 16
src/main/java/nju/seec/helper/service/impl/CourseServiceImpl.java

@@ -8,6 +8,7 @@ import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.modify.ModifyCourseDTO;
 import nju.seec.helper.entity.Choose;
 import nju.seec.helper.entity.Course;
+import nju.seec.helper.service.AuthUtil;
 import nju.seec.helper.service.CourseService;
 import nju.seec.helper.util.EncryptUtils;
 import nju.seec.helper.util.exception.HelperException;
@@ -35,12 +36,11 @@ public class CourseServiceImpl implements CourseService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public CourseVO createCourse(LoginUser teacher, CourseDTO courseDTO) {
-        Integer teacherId = teacher.getId();
-        if (courseDAO.existsByNameAndTeacherId(courseDTO.getName(), teacherId)) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "该课程名已使用");
-        }
+        // 检查
+        checkSameCourseName(teacher.getId(), courseDTO.getName());
+
         Course course = new Course()
-                .setTeacherId(teacherId)
+                .setTeacherId(teacher.getId())
                 .setTeacherName(teacher.getName())
                 .setName(courseDTO.getName())
                 .setBio(courseDTO.getBio())
@@ -50,19 +50,29 @@ public class CourseServiceImpl implements CourseService {
     }
 
     @Override
-    public CourseVO modifyCourse(LoginUser teacher, ModifyCourseDTO modifyCourseDTO) {
+    public CourseVO modifyCourse(LoginUser user, ModifyCourseDTO modifyCourseDTO) {
         Course course = courseDAO.findCourseById(modifyCourseDTO.getId());
-        if (!course.getTeacherId().equals(teacher.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权修改该课程");
-        }
+
+        // 检查
+        AuthUtil.checkDataAuth(user.getId(), course.getTeacherId(), "您无权修改该课程");
+        checkSameCourseName(user.getId(), modifyCourseDTO.getName());
+
         course.setName(modifyCourseDTO.getName())
-                .setCode(EncryptUtils.encode(modifyCourseDTO.getCode()))
                 .setBio(modifyCourseDTO.getBio())
-                .setCover(modifyCourseDTO.getCover());
+                .setCode(EncryptUtils.encode(modifyCourseDTO.getCode()));
         course = courseDAO.save(course);
         return new CourseVO(course);
     }
 
+    @Override
+    public void removeCourse(LoginUser user, Integer courseId) {
+        Course course = courseDAO.findCourseById(courseId);
+        AuthUtil.checkDataAuth(user.getId(), course.getTeacherId(), "您无权删除该课程");
+
+        course.setDeleteAt(System.currentTimeMillis());
+        courseDAO.save(course);
+    }
+
     @Transactional(rollbackFor = Exception.class)
     @Override
     public void chooseCourse(LoginUser student, ChooseDTO chooseDTO) {
@@ -85,9 +95,9 @@ public class CourseServiceImpl implements CourseService {
 
     @Transactional(readOnly = true)
     @Override
-    public List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable) {
+    public List<CourseVO> getCourses(String key, Pageable pageable) {
         return courseDAO
-                .findByTeacherIdAndNameContains(teacher.getId(), key, pageable)
+                .findByKey(key, pageable)
                 .stream()
                 .map(CourseVO::new)
                 .collect(Collectors.toList());
@@ -95,9 +105,9 @@ public class CourseServiceImpl implements CourseService {
 
     @Transactional(readOnly = true)
     @Override
-    public List<CourseVO> getCourses(String key, Pageable pageable) {
+    public List<CourseVO> teacherGetCourses(LoginUser teacher, String key, Pageable pageable) {
         return courseDAO
-                .findByNameContains(key, pageable)
+                .findByTeacherIdAndKey(teacher.getId(), key, pageable)
                 .stream()
                 .map(CourseVO::new)
                 .collect(Collectors.toList());
@@ -107,7 +117,7 @@ public class CourseServiceImpl implements CourseService {
     @Override
     public List<CourseVO> studentGetCourses(LoginUser student, String key, Pageable pageable) {
         return courseDAO
-                .findByIdInAndNameContains(
+                .findByIdsAndKey(
                         chooseDAO.findCourseIdsByStudentId(student.getId()),
                         key,
                         pageable)
@@ -115,4 +125,13 @@ public class CourseServiceImpl implements CourseService {
                 .map(CourseVO::new)
                 .collect(Collectors.toList());
     }
+
+    /**
+     * 检查同名课程
+     */
+    private void checkSameCourseName(Integer teacherId, String name) {
+        if (courseDAO.existsByTeacherIdAndName(teacherId, name)) {
+            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该课程名已使用");
+        }
+    }
 }

+ 3 - 6
src/main/java/nju/seec/helper/service/impl/ReplyServiceImpl.java

@@ -8,6 +8,7 @@ import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.ReplyDTO;
 import nju.seec.helper.entity.Comment;
 import nju.seec.helper.entity.Reply;
+import nju.seec.helper.service.AuthUtil;
 import nju.seec.helper.service.ReplyService;
 import nju.seec.helper.util.exception.HelperException;
 import nju.seec.helper.vo.ReplyVO;
@@ -34,9 +35,7 @@ public class ReplyServiceImpl implements ReplyService {
     @Override
     public ReplyVO createReply(LoginUser user, ReplyDTO replyDTO) {
         Comment comment = commentDAO.findCommentById(replyDTO.getCommentId());
-        if (!slideDAO.findSlideById(comment.getSlideId()).getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权回复该评论");
-        }
+        AuthUtil.checkDataAuth(user.getId(), slideDAO.findSlideById(comment.getSlideId()).getTeacherId(), "您无权回复该评论");
 
         if (comment.getReply() != null) {
             throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您已回复该评论");
@@ -54,9 +53,7 @@ public class ReplyServiceImpl implements ReplyService {
     @Override
     public void removeReply(LoginUser user, Integer replyId) {
         Reply reply = replyDAO.findReplyById(replyId);
-        if (!reply.getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权删除该回复");
-        }
+        AuthUtil.checkDataAuth(user.getId(), reply.getTeacherId(), "您无权回复该评论");
 
         Comment comment = reply.getComment();
         comment.setReply(null);

+ 20 - 12
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -1,6 +1,7 @@
 package nju.seec.helper.service.impl;
 
 import com.google.common.collect.ImmutableSet;
+import lombok.Cleanup;
 import lombok.SneakyThrows;
 import nju.seec.helper.dao.ChooseDAO;
 import nju.seec.helper.dao.CourseDAO;
@@ -10,6 +11,7 @@ import nju.seec.helper.dto.SlideDTO;
 import nju.seec.helper.dto.modify.ModifySlideDTO;
 import nju.seec.helper.entity.Course;
 import nju.seec.helper.entity.Slide;
+import nju.seec.helper.service.AuthUtil;
 import nju.seec.helper.service.SlideService;
 import nju.seec.helper.util.CacheUtils;
 import nju.seec.helper.util.Consts;
@@ -23,6 +25,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.InputStream;
 import java.time.LocalDateTime;
 import java.util.List;
 import java.util.Objects;
@@ -56,9 +59,7 @@ public class SlideServiceImpl implements SlideService {
     @Override
     public SlideVO createSlide(LoginUser teacher, SlideDTO slideDTO) {
         Course course = courseDAO.findCourseById(slideDTO.getCourseId());
-        if (!course.getTeacherId().equals(teacher.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权创建该课程的幻灯片");
-        }
+        AuthUtil.checkDataAuth(teacher.getId(), course.getTeacherId(), "您无权创建该课程的幻灯片");
 
         Slide slide = new Slide()
                 .setCourseId(slideDTO.getCourseId())
@@ -72,7 +73,8 @@ public class SlideServiceImpl implements SlideService {
         switch (Objects.requireNonNull(file.getContentType())) {
             // pdf
             case "application/pdf":
-                PDDocument doc = PDDocument.load(file.getInputStream());
+                @Cleanup InputStream fileInputStream = file.getInputStream();
+                PDDocument doc = PDDocument.load(fileInputStream);
                 pages = doc.getNumberOfPages();
                 break;
             default:
@@ -92,15 +94,23 @@ public class SlideServiceImpl implements SlideService {
     @Override
     public SlideVO modifySlide(LoginUser user, ModifySlideDTO modifySlideDTO) {
         Slide slide = slideDAO.findSlideById(modifySlideDTO.getId());
-        if (!slide.getTeacherId().equals(user.getId())) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权修改该幻灯片");
-        }
+        AuthUtil.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权修改该幻灯片");
+
         slide.setName(modifySlideDTO.getName())
                 .setState(modifySlideDTO.getState());
         slide = slideDAO.save(slide);
         return new SlideVO(slide);
     }
 
+    @Override
+    public void removeSlide(LoginUser user, Integer slideId) {
+        Slide slide = slideDAO.findSlideById(slideId);
+        AuthUtil.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权删除该幻灯片");
+
+        slide.setDeleteAt(System.currentTimeMillis());
+        slideDAO.save(slide);
+    }
+
     @Transactional(readOnly = true)
     @Override
     public List<SlideVO> teacherGetSlides(LoginUser teacher, String key, Pageable pageable) {
@@ -138,24 +148,22 @@ public class SlideServiceImpl implements SlideService {
     @Transactional(readOnly = true)
     @Override
     public String getSlideUrl(LoginUser user, Integer slideId) {
-        checkDataAccessAuth(user, slideId);
 
         Slide slide = slideDAO.findSlideById(slideId);
-        String url = cacheUtils.get(Consts.SLIDE_URL_CACHE_NAME, slide.getObjectName());
+        checkDataAccessAuth(user, slide);
 
+        String url = cacheUtils.get(Consts.SLIDE_URL_CACHE_NAME, slide.getObjectName());
         if (url != null) {
             return url;
         }
-
         url = fileUtils.getUrl(slide.getObjectName(), SLIDE_URL_LIVING_SECONDS);
         cacheUtils.set(Consts.SLIDE_URL_CACHE_NAME, slide.getObjectName(), url, SLIDE_URL_LIVING_SECONDS, TimeUnit.SECONDS);
         return url;
     }
 
-    private void checkDataAccessAuth(LoginUser user, Integer slideId) {
+    private void checkDataAccessAuth(LoginUser user, Slide slide) {
         HelperException forbiddenEx = HelperException.of(HelperException.ExceptionType.FORBIDDEN, "您无权访问该幻灯片");
 
-        Slide slide = slideDAO.findSlideById(slideId);
         switch (user.getType()) {
             case TEACHER:
                 if (!slide.getTeacherId().equals(user.getId())) {

+ 38 - 14
src/main/java/nju/seec/helper/service/impl/UserServiceImpl.java

@@ -4,8 +4,10 @@ import com.google.common.collect.ImmutableMap;
 import nju.seec.helper.dao.UserDAO;
 import nju.seec.helper.dto.LoginUser;
 import nju.seec.helper.dto.RegisterDTO;
+import nju.seec.helper.dto.ResetPasswordDTO;
 import nju.seec.helper.dto.modify.ModifyUserDTO;
 import nju.seec.helper.entity.User;
+import nju.seec.helper.service.AuthUtil;
 import nju.seec.helper.service.UserService;
 import nju.seec.helper.util.CacheUtils;
 import nju.seec.helper.util.Consts;
@@ -39,15 +41,12 @@ public class UserServiceImpl implements UserService {
     @Transactional(rollbackFor = Exception.class)
     @Override
     public UserVO createUser(RegisterDTO registerDTO) {
-        if (userDAO.existsByEmail(registerDTO.getEmail())) {
-            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该邮箱已注册");
-        } else if (userDAO.existsByPhone(registerDTO.getPhone())) {
-            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该手机号已注册");
-        }
+        checkSameEmail(registerDTO.getEmail());
+        checkSamePhone(registerDTO.getPhone());
 
         String email = registerDTO.getEmail();
         if (!registerDTO.getEmailCode().equals(cacheUtils.get(Consts.EMAIL_CACHE_NAME, email))) {
-            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "邮箱验证码错误");
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "邮箱验证码错误");
         }
 
         User user = new User()
@@ -66,6 +65,29 @@ public class UserServiceImpl implements UserService {
         return EMAIL_SUFFIX_AND_USER_TYPE_MAP.get(email.substring(email.indexOf("@") + 1));
     }
 
+    @Override
+    public UserVO modifyUser(LoginUser loginUser, ModifyUserDTO modifyUserDTO) {
+        User user = userDAO.findUserById(loginUser.getId());
+        AuthUtil.checkDataAuth(loginUser.getId(), user.getId(), "您无权修改该用户的个人信息");
+        user.setName(modifyUserDTO.getName());
+        user = userDAO.save(user);
+        return new UserVO(user);
+    }
+
+    @Override
+    public void resetPasswordByEmail(ResetPasswordDTO resetPasswordDTO) {
+        User user = userDAO.findByEmail(resetPasswordDTO.getUsername())
+                .orElseThrow(() -> HelperException.of(HelperException.ExceptionType.FORBIDDEN, "该邮箱未在系统中注册"));
+
+        if (!resetPasswordDTO.getCode().equals(cacheUtils.get(Consts.EMAIL_CACHE_NAME, resetPasswordDTO.getUsername()))) {
+            throw HelperException.of(HelperException.ExceptionType.FORBIDDEN, "邮箱或验证码错误");
+        }
+
+        user.setPassword(EncryptUtils.encode(resetPasswordDTO.getPassword()));
+        userDAO.save(user);
+        cacheUtils.remove(Consts.EMAIL_CACHE_NAME, resetPasswordDTO.getUsername());
+    }
+
     @Transactional(readOnly = true)
     @Override
     public UserVO getUserByEmailAndPassword(String email, String password) {
@@ -81,13 +103,15 @@ public class UserServiceImpl implements UserService {
         return new UserVO(userDAO.findUserById(userId));
     }
 
-    @Override
-    public UserVO modifyUser(LoginUser loginUser, ModifyUserDTO modifyUserDTO) {
-        User user = userDAO
-                .findUserById(loginUser.getId())
-                .setName(modifyUserDTO.getName())
-                .setPassword(EncryptUtils.encode(modifyUserDTO.getPassword()));
-        user = userDAO.save(user);
-        return new UserVO(user);
+    private void checkSameEmail(String email) {
+        if (userDAO.existsByEmail(email)) {
+            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该邮箱已注册");
+        }
+    }
+
+    private void checkSamePhone(String phone) {
+        if (userDAO.existsByPhone(phone)) {
+            throw HelperException.of(HelperException.ExceptionType.CONFLICT, "该手机号已注册");
+        }
     }
 }

+ 6 - 0
src/main/java/nju/seec/helper/util/EncryptUtils.java

@@ -9,10 +9,16 @@ import java.util.Base64;
  */
 @UtilityClass
 public class EncryptUtils {
+    /**
+     * 加密
+     */
     public String encode(String string) {
         return Base64.getEncoder().encodeToString(string.getBytes());
     }
 
+    /**
+     * 解密
+     */
     public String decode(String string) {
         return new String(Base64.getDecoder().decode(string));
     }

+ 0 - 2
src/main/java/nju/seec/helper/vo/CourseVO.java

@@ -14,7 +14,6 @@ public class CourseVO {
     private Integer id;
     private String name;
     private String bio;
-    private String cover;
     private LocalDateTime createAt;
 
     private Integer teacherId;
@@ -24,7 +23,6 @@ public class CourseVO {
         this.id = course.getId();
         this.name = course.getName();
         this.bio = course.getBio();
-        this.cover = course.getCover();
         this.createAt = course.getCreateAt();
 
         this.teacherId = course.getTeacherId();

+ 4 - 4
src/main/resources/application-dev.yml

@@ -22,9 +22,9 @@ spring:
       repositories:
         enabled: false
   mail:
-    host: smtp.qq.com
-    username: chen_st@foxmail.com
-    password: jgeiyvaojagnecjd
+    host: smtp.163.com
+    username: seecoder@163.com
+    password: seec67NJU
     properties:
       mail:
         smtp:
@@ -49,4 +49,4 @@ aliyun:
 # 自定义数据
 helper:
   mail:
-    from: ${spring.mail.username}
+    from: ${spring.mail.username}