Prechádzať zdrojové kódy

feat: 增加告示功能

ChenSiTong 6 rokov pred
rodič
commit
165a4d919f

+ 11 - 1
src/main/java/nju/seec/helper/controller/CommentController.java

@@ -69,6 +69,16 @@ public class CommentController {
         commentService.unTopComment(user, commentId);
     }
 
+    /**
+     *
+     */
+    @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "获取评论")
+    @GetMapping("/slide/{slideId}/all")
+    public PageResponse<CommentVO> getAllComments(@PathVariable Long slideId,
+                                                  @PageableDefault(Integer.MAX_VALUE) Pageable pageable) {
+        return PageResponse.of(commentService.getCommentsBySlide(slideId, pageable));
+    }
+
     /**
      * 取得某一页的评论信息
      */
@@ -77,7 +87,7 @@ public class CommentController {
     public PageResponse<CommentVO> getComments(@PathVariable Long slideId,
                                                @RequestParam(required = false, defaultValue = "1") Integer pageNumber,
                                                @PageableDefault(Integer.MAX_VALUE) Pageable pageable) {
-        return PageResponse.of(commentService.getCommentsBySlideIdAndPageNumber(slideId, pageNumber, pageable));
+        return PageResponse.of(commentService.getCommentsBySlideAndPageNumber(slideId, pageNumber, pageable));
     }
 
     /**

+ 58 - 0
src/main/java/nju/seec/helper/controller/NoticeController.java

@@ -0,0 +1,58 @@
+package nju.seec.helper.controller;
+
+import nju.seec.helper.aspect.auth.Auth;
+import nju.seec.helper.controller.response.PageResponse;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.NoticeDTO;
+import nju.seec.helper.dto.groups.Create;
+import nju.seec.helper.dto.groups.Modify;
+import nju.seec.helper.service.NoticeService;
+import nju.seec.helper.util.enums.UserType;
+import nju.seec.helper.vo.NoticeVO;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author cst
+ */
+@RestController
+@RequestMapping("/api/notice")
+public class NoticeController {
+    private final NoticeService noticeService;
+
+    public NoticeController(NoticeService noticeService) {
+        this.noticeService = noticeService;
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "发布公告")
+    @PostMapping
+    public NoticeVO createNotice(LoginUser user,
+                                 @Validated(Create.class) @RequestBody NoticeDTO noticeDTO) {
+        return noticeService.create(user, noticeDTO);
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "修改公告")
+    @PutMapping
+    public NoticeVO modifyNotice(LoginUser user,
+                                 @Validated(Modify.class) @RequestBody NoticeDTO noticeDTO) {
+        return noticeService.modify(user, noticeDTO);
+    }
+
+    @Auth(roles = UserType.TEACHER, message = "删除公告")
+    @DeleteMapping("/{noticeId}")
+    public void removeNotice(LoginUser user,
+                             @PathVariable Long noticeId) {
+        noticeService.deleteNotice(user, noticeId);
+    }
+
+    @Auth(roles = {UserType.TEACHER, UserType.STUDENT}, message = "获取公告")
+    @GetMapping("/course/{courseId}")
+    public PageResponse<NoticeVO> getNotices(LoginUser user,
+                                             @PathVariable Long courseId,
+                                             @RequestParam(defaultValue = "") String key,
+                                             @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable) {
+        return PageResponse.of(noticeService.getNoticesByCourse(user, courseId, key, pageable));
+    }
+}

+ 1 - 1
src/main/java/nju/seec/helper/dao/CommentDAO.java

@@ -53,7 +53,7 @@ public interface CommentDAO extends JpaRepository<Comment, Long> {
             "where c.slideId=?1 " +
             "and c.pageNumber=?2 " +
             "order by nullif(c.topNumber, 0) desc")
-    Page<Comment> findComments(Long slideId, Integer pageNumber, Pageable pageable);
+    Page<Comment> findBySlideIdAndPageNumber(Long slideId, Integer pageNumber, Pageable pageable);
 
     /**
      * 置顶减一

+ 40 - 0
src/main/java/nju/seec/helper/dao/NoticeDAO.java

@@ -0,0 +1,40 @@
+package nju.seec.helper.dao;
+
+import nju.seec.helper.entity.Notice;
+import nju.seec.helper.util.enums.ExceptionType;
+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;
+
+/**
+ * @author cst
+ */
+@Repository
+public interface NoticeDAO extends JpaRepository<Notice, Long> {
+    /**
+     * 封装findById
+     *
+     * @param id
+     * @return
+     */
+    default Notice findNoticeById(Long id) {
+        return this.findById(id)
+                .orElseThrow(() -> HelperException.of(ExceptionType.NOT_FOUND, "找不到公告"));
+    }
+
+    /**
+     * 根据课程ID查找
+     *
+     * @param courseId
+     * @param key
+     * @param pageable
+     * @return
+     */
+    @Query("select n from Notice n " +
+            "where n.courseId=?1 " +
+            "and (n.title like concat('%',?2,'%') or n.content like concat('%',?2,'%') )")
+    Page<Notice> findByCourseIdAndKey(Long courseId, String key, Pageable pageable);
+}

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

@@ -0,0 +1,27 @@
+package nju.seec.helper.dto;
+
+import lombok.Data;
+import nju.seec.helper.dto.groups.Create;
+import nju.seec.helper.dto.groups.Modify;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author cst
+ */
+@Data
+public class NoticeDTO {
+    @NotNull(message = "缺少公告ID", groups = Modify.class)
+    private Long id;
+    @NotNull(message = "缺少课程ID", groups = Create.class)
+    private Long courseId;
+    @NotBlank(message = "标题不能为空")
+    @Length(max = 50, message = "标题长度不能超过50")
+    private String title;
+
+    @NotBlank(message = "内容不能为空")
+    @Length(max = 1000, message = "内容长度不能超过1000")
+    private String content;
+}

+ 43 - 0
src/main/java/nju/seec/helper/entity/Notice.java

@@ -0,0 +1,43 @@
+package nju.seec.helper.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.hibernate.annotations.CreationTimestamp;
+import org.hibernate.annotations.UpdateTimestamp;
+
+import javax.persistence.*;
+import java.time.LocalDateTime;
+
+/**
+ * @author cst
+ */
+@Data
+@Accessors(chain = true)
+@Entity
+@Table(name = "notice")
+public class Notice {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "course_id", nullable = false)
+    private Long courseId;
+
+    @Column(name = "teacher_id", nullable = false)
+    private Long teacherId;
+
+    @Column(nullable = false)
+    private String title;
+
+    @Lob
+    @Column(columnDefinition = "text", nullable = false)
+    private String content;
+
+    @Column(name = "create_at", nullable = false, updatable = false)
+    @CreationTimestamp
+    private LocalDateTime createAt;
+
+    @Column(name = "update_at", nullable = false)
+    @UpdateTimestamp
+    private LocalDateTime updateAt;
+}

+ 10 - 1
src/main/java/nju/seec/helper/service/CommentService.java

@@ -51,7 +51,16 @@ public interface CommentService {
      * @param pageable
      * @return
      */
-    Page<CommentVO> getCommentsBySlideIdAndPageNumber(Long slideId, Integer pageNumber, Pageable pageable);
+    Page<CommentVO> getCommentsBySlideAndPageNumber(Long slideId, Integer pageNumber, Pageable pageable);
+
+    /**
+     * 基于课件取得评论
+     *
+     * @param slideId
+     * @param pageable
+     * @return
+     */
+    Page<CommentVO> getCommentsBySlide(Long slideId, Pageable pageable);
 
     /**
      * 获得某条评论

+ 49 - 0
src/main/java/nju/seec/helper/service/NoticeService.java

@@ -0,0 +1,49 @@
+package nju.seec.helper.service;
+
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.NoticeDTO;
+import nju.seec.helper.vo.NoticeVO;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+/**
+ * @author cst
+ */
+public interface NoticeService {
+    /**
+     * 创建公告
+     *
+     * @param user
+     * @param noticeDTO
+     * @return
+     */
+    NoticeVO create(LoginUser user, NoticeDTO noticeDTO);
+
+    /**
+     * 修改公告
+     *
+     * @param user
+     * @param noticeDTO
+     * @return
+     */
+    NoticeVO modify(LoginUser user, NoticeDTO noticeDTO);
+
+    /**
+     * 取得公告
+     *
+     * @param user
+     * @param courseId
+     * @param key
+     * @param pageable
+     * @return
+     */
+    Page<NoticeVO> getNoticesByCourse(LoginUser user, Long courseId, String key, Pageable pageable);
+
+    /**
+     * 删除告示
+     *
+     * @param user
+     * @param noticeId
+     */
+    void deleteNotice(LoginUser user, Long noticeId);
+}

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

@@ -50,7 +50,7 @@ public class CommentServiceImpl implements CommentService {
         // 增加通知
         Slide slide = slideDAO.findSlideById(comment.getSlideId());
         if (!user.getId().equals(slide.getTeacherId())) {
-            messageService.createMessage(Collections.singleton(slide.getTeacherId()), MessageType.COMMENT_NEW, String.format("课程 [%s] 的课件 [%s] 有主题为 [%s] 的新评论", slide.getCourseName(), slide.getName(), comment.getTitle()), slide.getId());
+            messageService.createMessage(Collections.singleton(slide.getTeacherId()), MessageType.COMMENT_NEW, String.format("课程 [%s] 的课件 [%s] 在第%d页有新评论", slide.getCourseName(), slide.getName(), comment.getPageNumber()), slide.getId());
         }
 
         return new CommentVO(comment);
@@ -100,8 +100,15 @@ public class CommentServiceImpl implements CommentService {
 
     @Transactional(readOnly = true)
     @Override
-    public Page<CommentVO> getCommentsBySlideIdAndPageNumber(Long slideId, Integer pageNumber, Pageable pageable) {
-        return commentDAO.findComments(slideId, pageNumber, pageable).map(CommentVO::new);
+    public Page<CommentVO> getCommentsBySlideAndPageNumber(Long slideId, Integer pageNumber, Pageable pageable) {
+        return commentDAO.findBySlideIdAndPageNumber(slideId, pageNumber, pageable).map(CommentVO::new);
+    }
+
+    @Transactional(readOnly = true)
+    @Override
+    public Page<CommentVO> getCommentsBySlide(Long slideId, Pageable pageable) {
+        // TODO
+        return Page.empty();
     }
 
     @Transactional(readOnly = true)

+ 74 - 0
src/main/java/nju/seec/helper/service/impl/NoticeServiceImpl.java

@@ -0,0 +1,74 @@
+package nju.seec.helper.service.impl;
+
+import nju.seec.helper.dao.ChooseDAO;
+import nju.seec.helper.dao.CourseDAO;
+import nju.seec.helper.dao.NoticeDAO;
+import nju.seec.helper.dto.LoginUser;
+import nju.seec.helper.dto.NoticeDTO;
+import nju.seec.helper.entity.Course;
+import nju.seec.helper.entity.Notice;
+import nju.seec.helper.service.MessageService;
+import nju.seec.helper.service.NoticeService;
+import nju.seec.helper.service.util.AuthUtils;
+import nju.seec.helper.util.enums.MessageType;
+import nju.seec.helper.vo.NoticeVO;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+import java.util.Set;
+
+/**
+ * @author cst
+ */
+@Service
+public class NoticeServiceImpl implements NoticeService {
+    private final CourseDAO courseDAO;
+    private final ChooseDAO chooseDAO;
+    private final NoticeDAO noticeDAO;
+
+    private final MessageService messageService;
+
+    public NoticeServiceImpl(CourseDAO courseDAO, ChooseDAO chooseDAO, NoticeDAO noticeDAO, MessageService messageService) {
+        this.courseDAO = courseDAO;
+        this.chooseDAO = chooseDAO;
+        this.noticeDAO = noticeDAO;
+        this.messageService = messageService;
+    }
+
+    @Override
+    public NoticeVO create(LoginUser user, NoticeDTO noticeDTO) {
+        Course course = courseDAO.findCourseById(noticeDTO.getCourseId());
+        AuthUtils.checkDataAuth(user.getId(), course.getTeacherId(), "您无权创建该课程的公告");
+        Notice notice = new Notice()
+                .setCourseId(noticeDTO.getCourseId())
+                .setTeacherId(user.getId())
+                .setTitle(noticeDTO.getTitle())
+                .setContent(noticeDTO.getContent());
+
+        Set<Long> studentIds = chooseDAO.findStudentIdsByCourseId(noticeDTO.getCourseId());
+        messageService.createMessage(studentIds, MessageType.NOTICE_NEW, String.format("课程 [%s] 发布了标题为 [%s] 的公告", course.getName(), notice.getTitle()), null);
+        return new NoticeVO(noticeDAO.save(notice));
+    }
+
+    @Override
+    public NoticeVO modify(LoginUser user, NoticeDTO noticeDTO) {
+        Notice notice = noticeDAO.findNoticeById(noticeDTO.getId());
+        AuthUtils.checkDataAuth(user.getId(), notice.getTeacherId(), "您无权修改该公告");
+        notice.setTitle(noticeDTO.getTitle())
+                .setContent(noticeDTO.getContent());
+        return new NoticeVO(noticeDAO.save(notice));
+    }
+
+    @Override
+    public Page<NoticeVO> getNoticesByCourse(LoginUser user, Long courseId, String key, Pageable pageable) {
+        return noticeDAO.findByCourseIdAndKey(courseId, key, pageable).map(NoticeVO::new);
+    }
+
+    @Override
+    public void deleteNotice(LoginUser user, Long noticeId) {
+        Notice notice = noticeDAO.findNoticeById(noticeId);
+        AuthUtils.checkDataAuth(user.getId(), notice.getTeacherId(), "您无权删除该公告");
+        noticeDAO.deleteById(noticeId);
+    }
+}

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

@@ -59,7 +59,7 @@ public class ReplyServiceImpl implements ReplyService {
         // 增加通知
         if (!user.getId().equals(comment.getUserId())) {
             Slide slide = slideDAO.findSlideById(comment.getSlideId());
-            messageService.createMessage(Collections.singleton(comment.getUserId()), MessageType.COMMENT_REPLY, String.format("您在课件 [%s] 发表的题为 [%s] 的讨论帖已收到回复", slide.getName(), comment.getTitle()), slide.getId());
+            messageService.createMessage(Collections.singleton(comment.getUserId()), MessageType.COMMENT_REPLY, String.format("您在课件 [%s] 第%d页发表的讨论帖已收到回复", slide.getName(), comment.getPageNumber()), slide.getId());
         }
 
         return new ReplyVO(reply);

+ 0 - 4
src/main/java/nju/seec/helper/service/impl/SlideServiceImpl.java

@@ -138,10 +138,6 @@ public class SlideServiceImpl implements SlideService {
         Slide slide = slideDAO.findSlideById(slideFileDTO.getId());
         AuthUtils.checkDataAuth(user.getId(), slide.getTeacherId(), "您无权修改该课件文件");
 
-        if (slide.getState() != SlideState.DRAFT) {
-            throw HelperException.of(ExceptionType.FORBIDDEN, "该课件非草稿状态,无法修改其文件");
-        }
-
         MultipartFile file = slideFileDTO.getFile();
         FileInfo fileInfo = getFileInfo(file);
         slide.setPages(fileInfo.pages);

+ 2 - 2
src/main/java/nju/seec/helper/service/util/AuthUtils.java

@@ -10,8 +10,8 @@ import nju.seec.helper.util.exception.HelperException;
  */
 @UtilityClass
 public class AuthUtils {
-    public void checkDataAuth(@NonNull Long userId, @NonNull Long dateUserId, String errMsg) {
-        if (!userId.equals(dateUserId)) {
+    public void checkDataAuth(@NonNull Long userId, @NonNull Long dataUserId, String errMsg) {
+        if (!userId.equals(dataUserId)) {
             throw HelperException.of(ExceptionType.FORBIDDEN, errMsg);
         }
     }

+ 5 - 1
src/main/java/nju/seec/helper/util/enums/MessageType.java

@@ -15,5 +15,9 @@ public enum MessageType {
     /**
      * 评论被老师回复
      */
-    COMMENT_REPLY
+    COMMENT_REPLY,
+    /**
+     * 新公告
+     */
+    NOTICE_NEW
 }

+ 28 - 0
src/main/java/nju/seec/helper/vo/NoticeVO.java

@@ -0,0 +1,28 @@
+package nju.seec.helper.vo;
+
+import lombok.Data;
+import nju.seec.helper.entity.Notice;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author cst
+ */
+@Data
+public class NoticeVO {
+    private Long id;
+    private Long courseId;
+    private String title;
+    private String content;
+    private LocalDateTime createAt;
+    private LocalDateTime updateAt;
+
+    public NoticeVO(Notice notice) {
+        this.id = notice.getId();
+        this.courseId = notice.getCourseId();
+        this.title = notice.getTitle();
+        this.content = notice.getContent();
+        this.createAt = notice.getCreateAt();
+        this.updateAt = notice.getUpdateAt();
+    }
+}