QuizServiceImpl.java 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package nju.seec.helper.service.impl;
  2. import com.google.common.collect.ImmutableSet;
  3. import nju.seec.helper.dao.*;
  4. import nju.seec.helper.dto.quiz.QuizDTO;
  5. import nju.seec.helper.aspect.auth.LoginUser;
  6. import nju.seec.helper.entity.Course;
  7. import nju.seec.helper.entity.Quiz;
  8. import nju.seec.helper.entity.Slide;
  9. import nju.seec.helper.service.MessageService;
  10. import nju.seec.helper.service.QuizService;
  11. import nju.seec.helper.service.util.AuthUtils;
  12. import nju.seec.helper.service.util.StringUtils;
  13. import nju.seec.helper.enums.*;
  14. import nju.seec.helper.exception.HelperException;
  15. import nju.seec.helper.vo.quiz.QuizVO;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.data.domain.Page;
  18. import org.springframework.data.domain.Pageable;
  19. import org.springframework.data.jpa.domain.Specification;
  20. import org.springframework.stereotype.Service;
  21. import org.springframework.transaction.annotation.Transactional;
  22. import java.util.List;
  23. import java.util.Set;
  24. /**
  25. * @author xst
  26. * <p>
  27. * updated by cst
  28. */
  29. @Service
  30. public class QuizServiceImpl implements QuizService {
  31. private final SlideDAO slideDAO;
  32. private final QuizDAO quizDAO;
  33. private final QuizStudentAnswerDAO quizStudentAnswerDAO;
  34. private final ChooseDAO chooseDAO;
  35. private final CourseDAO courseDAO;
  36. private final UserDAO userDAO;
  37. private final MessageService messageService;
  38. @Autowired
  39. public QuizServiceImpl(SlideDAO slideDAO, QuizDAO quizDAO, QuizStudentAnswerDAO quizStudentAnswerDAO, ChooseDAO chooseDAO, CourseDAO courseDAO, UserDAO userDAO, MessageService messageService) {
  40. this.slideDAO = slideDAO;
  41. this.quizDAO = quizDAO;
  42. this.quizStudentAnswerDAO = quizStudentAnswerDAO;
  43. this.chooseDAO = chooseDAO;
  44. this.courseDAO = courseDAO;
  45. this.userDAO = userDAO;
  46. this.messageService = messageService;
  47. }
  48. @Transactional(rollbackFor = Exception.class)
  49. @Override
  50. public QuizVO createQuiz(LoginUser user, QuizDTO quizDTO) {
  51. Slide slide = slideDAO.findSlideById(quizDTO.getSlideId());
  52. AuthUtils.checkDataAuth(user.getId(), slide.getTeacher().getId(), "您无权创建该课件的测试");
  53. checkSameName(0L, quizDTO.getSlideId(), quizDTO.getName());
  54. checkQuizTypeOkToSlideState(slide.getState(), quizDTO.getType());
  55. Quiz quiz = new Quiz()
  56. .setCourse(slide.getCourse())
  57. .setSlide(slide)
  58. .setTeacher(slide.getTeacher())
  59. .setType(quizDTO.getType())
  60. .setState(QuizState.getQuizStateBySlideStateAndQuizType(slide.getState(), quizDTO.getType()))
  61. .setName(quizDTO.getName())
  62. .setMaxSubmitNumber(quizDTO.getMaxSubmitTime())
  63. .setQuestions(quizDTO.getQuestions());
  64. return new QuizVO(quizDAO.save(quiz));
  65. }
  66. @Transactional(rollbackFor = Exception.class)
  67. @Override
  68. public QuizVO modifyQuiz(LoginUser user, Long quizId, QuizDTO quizDTO) {
  69. Quiz quiz = quizDAO.findQuizById(quizId);
  70. AuthUtils.checkDataAuth(user.getId(), quiz.getTeacher().getId(), "您无权修改该测试");
  71. checkSubmit(quiz);
  72. Slide slide = quiz.getSlide();
  73. checkQuizTypeOkToSlideState(slide.getState(), quizDTO.getType());
  74. checkSameName(quiz.getId(), quizDTO.getSlideId(), quizDTO.getName());
  75. quiz.setType(quizDTO.getType())
  76. .setState(QuizState.getQuizStateBySlideStateAndQuizType(slide.getState(), quizDTO.getType()))
  77. .setName(quizDTO.getName())
  78. .setMaxSubmitNumber(quizDTO.getMaxSubmitTime())
  79. .setQuestions(quizDTO.getQuestions());
  80. return new QuizVO(quizDAO.save(quiz));
  81. }
  82. private void checkSameName(Long quizId, Long slideId, String name) {
  83. long exists = quizDAO.count((Specification<Quiz>) (root, query, cb) ->
  84. cb.and(cb.notEqual(root.get("id"), quizId),
  85. cb.equal(root.get("slide").get("id"), slideId),
  86. cb.equal(root.get("name"), name)
  87. ));
  88. if (exists > 0) {
  89. throw HelperException.of(ExceptionType.CONFLICT, "该测试名已使用");
  90. }
  91. }
  92. private void checkQuizTypeOkToSlideState(SlideState slideState, QuizType quizType) {
  93. if (!QuizType.getQuizTypesBySlideState(slideState).contains(quizType)) {
  94. throw HelperException.of(ExceptionType.FORBIDDEN, "课件暂时不支持创建该类型的测试,请检查课件状态");
  95. }
  96. }
  97. private void checkSubmit(Quiz quiz) {
  98. if (quizStudentAnswerDAO.existsByQuiz(quiz)) {
  99. throw HelperException.of(ExceptionType.FORBIDDEN, "该测试已有提交,无法修改");
  100. }
  101. }
  102. @Transactional(rollbackFor = Exception.class)
  103. @Override
  104. public void deleteQuiz(LoginUser user, Long quizId) {
  105. Quiz quiz = quizDAO.findQuizById(quizId);
  106. AuthUtils.checkDataAuth(user.getId(), quiz.getTeacher().getId(), "您无权删除该测试");
  107. quiz.setDeleteAt(System.currentTimeMillis());
  108. quizDAO.save(quiz);
  109. }
  110. @Transactional(readOnly = true)
  111. @Override
  112. public Page<QuizVO> teacherGetQuizzesBySlide(LoginUser user, Long slideId, String key, Pageable pageable) {
  113. return findBySlideIdAndKey(slideId, key, pageable).map(QuizVO::new);
  114. }
  115. public static final Set<QuizState> STATES_NOT_GET_BY_STUDENT_SET = ImmutableSet.of(QuizState.NOT_STARTED);
  116. @Transactional(readOnly = true)
  117. @Override
  118. public Page<QuizVO> studentGetQuizzesBySlide(LoginUser user, Long slideId, String key, Pageable pageable) {
  119. return findBySlideIdAndStateNotInAndKey(slideId, STATES_NOT_GET_BY_STUDENT_SET, key, pageable).map(QuizVO::new);
  120. }
  121. @Transactional(readOnly = true)
  122. @Override
  123. public Page<QuizVO> studentGetQuizzesByState(LoginUser user, QuizState state, String key, Pageable pageable) {
  124. if (STATES_NOT_GET_BY_STUDENT_SET.contains(state)) {
  125. throw HelperException.of(ExceptionType.FORBIDDEN, "您暂时无法获取该状态的测试");
  126. }
  127. Set<Long> courseIds = chooseDAO.findCourseIdsByStudentId(user.getId());
  128. return findByCourseIdInAndStateAndKey(courseIds, state, key, pageable).map(QuizVO::new);
  129. }
  130. @Transactional(readOnly = true)
  131. @Override
  132. public QuizVO getOneQuiz(LoginUser user, Long quizId) {
  133. Quiz quiz = quizDAO.findQuizById(quizId);
  134. checkDataAccessAuth(user, quiz);
  135. return new QuizVO(quiz);
  136. }
  137. @Transactional(rollbackFor = Exception.class)
  138. @Override
  139. public void modifyQuizState(Slide slide) {
  140. List<Quiz> quizzes = quizDAO.findAllBySlide(slide);
  141. Course course = slide.getCourse();
  142. Set<Long> chooseStudentIds = chooseDAO.findStudentIdsByCourseId(course.getId());
  143. quizzes.forEach(quiz -> {
  144. QuizState quizState = QuizState.getQuizStateBySlideStateAndQuizType(slide.getState(), quiz.getType());
  145. quiz.setState(quizState);
  146. if (quizState == QuizState.ONGOING) {
  147. messageService.createMessage(chooseStudentIds, MessageType.QUIZ_NEW, String.format("[%s] - [%s] 的测试 [%s] 已开放", course.getName(), slide.getName(), quiz.getName()), slide.getId());
  148. }
  149. });
  150. }
  151. private void checkDataAccessAuth(LoginUser user, Quiz quiz) {
  152. HelperException forbiddenEx = HelperException.of(ExceptionType.FORBIDDEN, "您无权访问该测试");
  153. switch (user.getType()) {
  154. case TEACHER:
  155. break;
  156. case STUDENT:
  157. if (quiz.getState() == QuizState.NOT_STARTED) {
  158. throw forbiddenEx;
  159. }
  160. break;
  161. default:
  162. throw forbiddenEx;
  163. }
  164. }
  165. private Page<Quiz> findByCourseIdInAndStateAndKey(Set<Long> courseIds, QuizState state, String key, Pageable pageable) {
  166. return quizDAO.findAll(
  167. (Specification<Quiz>) (root, query, cb) -> cb.and(
  168. root.get("course").get("id").in(courseIds)
  169. , cb.equal(root.get("deleteAt"), 0L)
  170. , cb.equal(root.get("state"), state)
  171. , cb.like(root.get("name"), StringUtils.keyPattern(key))
  172. , cb.equal(root.get("slide").get("deleteAt"), 0L)
  173. , cb.equal(root.get("course").get("deleteAt"), 0L)
  174. ),
  175. pageable);
  176. }
  177. private Page<Quiz> findBySlideIdAndKey(Long slideId, String key, Pageable pageable) {
  178. return quizDAO.findAll(
  179. (Specification<Quiz>) (root, query, cb) -> cb.and(
  180. cb.equal(root.get("slide").get("id"), slideId)
  181. , cb.equal(root.get("deleteAt"), 0L)
  182. , cb.like(root.get("name"), StringUtils.keyPattern(key))
  183. , cb.equal(root.get("slide").get("deleteAt"), 0L)
  184. , cb.equal(root.get("course").get("deleteAt"), 0L)
  185. ),
  186. pageable);
  187. }
  188. private Page<Quiz> findBySlideIdAndStateNotInAndKey(Long slideId, Set<QuizState> exclusiveStates, String key, Pageable pageable) {
  189. return quizDAO.findAll(
  190. (Specification<Quiz>) (root, query, cb) -> cb.and(
  191. cb.equal(root.get("slide").get("id"), slideId)
  192. , cb.equal(root.get("deleteAt"), 0L)
  193. , cb.like(root.get("name"), StringUtils.keyPattern(key))
  194. , cb.not(root.get("state").in(exclusiveStates))
  195. , cb.equal(root.get("slide").get("deleteAt"), 0L)
  196. , cb.equal(root.get("course").get("deleteAt"), 0L)
  197. ),
  198. pageable);
  199. }
  200. }