|
|
@@ -1,8 +1,9 @@
|
|
|
package nju.seec.helper.service.impl;
|
|
|
|
|
|
import com.google.common.collect.ImmutableSet;
|
|
|
-import lombok.AllArgsConstructor;
|
|
|
+import com.google.common.io.Files;
|
|
|
import lombok.SneakyThrows;
|
|
|
+import nju.seec.helper.aspect.auth.LoginUser;
|
|
|
import nju.seec.helper.dao.ChooseDAO;
|
|
|
import nju.seec.helper.dao.CourseDAO;
|
|
|
import nju.seec.helper.dao.SlideDAO;
|
|
|
@@ -10,35 +11,30 @@ import nju.seec.helper.dao.UserDAO;
|
|
|
import nju.seec.helper.dto.slide.SlideDTO;
|
|
|
import nju.seec.helper.dto.slide.SlideFileDTO;
|
|
|
import nju.seec.helper.dto.slide.SlideStateDTO;
|
|
|
-import nju.seec.helper.dto.user.LoginUser;
|
|
|
import nju.seec.helper.entity.Course;
|
|
|
import nju.seec.helper.entity.Slide;
|
|
|
+import nju.seec.helper.enums.ExceptionType;
|
|
|
+import nju.seec.helper.enums.MessageType;
|
|
|
+import nju.seec.helper.enums.SlideState;
|
|
|
+import nju.seec.helper.exception.HelperException;
|
|
|
import nju.seec.helper.service.CourseService;
|
|
|
import nju.seec.helper.service.MessageService;
|
|
|
import nju.seec.helper.service.QuizService;
|
|
|
import nju.seec.helper.service.SlideService;
|
|
|
-import nju.seec.helper.service.util.AuthUtils;
|
|
|
-import nju.seec.helper.service.util.StringUtils;
|
|
|
-import nju.seec.helper.util.Consts;
|
|
|
-import nju.seec.helper.util.FileUtils;
|
|
|
-import nju.seec.helper.util.RedisCacheUtils;
|
|
|
-import nju.seec.helper.util.enums.ExceptionType;
|
|
|
-import nju.seec.helper.util.enums.MessageType;
|
|
|
-import nju.seec.helper.util.enums.SlideState;
|
|
|
-import nju.seec.helper.util.exception.HelperException;
|
|
|
+import nju.seec.helper.service.util.OssObjectUrlUtils;
|
|
|
+import nju.seec.helper.util.OssUtils;
|
|
|
+import nju.seec.helper.util.file.FileInfo;
|
|
|
+import nju.seec.helper.util.file.FileUtils;
|
|
|
import nju.seec.helper.vo.SlideVO;
|
|
|
-import org.apache.pdfbox.pdmodel.PDDocument;
|
|
|
+import org.springframework.dao.DataIntegrityViolationException;
|
|
|
import org.springframework.data.domain.Page;
|
|
|
import org.springframework.data.domain.Pageable;
|
|
|
-import org.springframework.data.jpa.domain.Specification;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import java.io.File;
|
|
|
-import java.util.Objects;
|
|
|
import java.util.Set;
|
|
|
-import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
/**
|
|
|
* @author cst
|
|
|
@@ -46,40 +42,37 @@ import java.util.concurrent.TimeUnit;
|
|
|
@Service
|
|
|
public class SlideServiceImpl implements SlideService {
|
|
|
private static final String SLIDE_STORE_DIR = "slide";
|
|
|
- private static final long SLIDE_URL_LIVING_SECONDS = 20 * 60;
|
|
|
|
|
|
private final CourseDAO courseDAO;
|
|
|
private final SlideDAO slideDAO;
|
|
|
private final ChooseDAO chooseDAO;
|
|
|
private final UserDAO userDAO;
|
|
|
|
|
|
- private final QuizService quizService;
|
|
|
- private final FileUtils fileUtils;
|
|
|
- private final RedisCacheUtils cacheUtils;
|
|
|
+ private final OssUtils ossUtils;
|
|
|
+ private final OssObjectUrlUtils ossObjectUrlUtils;
|
|
|
|
|
|
+ private final QuizService quizService;
|
|
|
private final MessageService messageService;
|
|
|
private final CourseService courseService;
|
|
|
|
|
|
- public SlideServiceImpl(CourseDAO courseDAO, SlideDAO slideDAO, ChooseDAO chooseDAO, UserDAO userDAO, FileUtils fileUtils, RedisCacheUtils cacheUtils, MessageService messageService, QuizService quizService, CourseService courseService) {
|
|
|
+ public SlideServiceImpl(CourseDAO courseDAO, SlideDAO slideDAO, ChooseDAO chooseDAO, UserDAO userDAO, OssUtils ossUtils, OssObjectUrlUtils ossObjectUrlUtils, QuizService quizService, MessageService messageService, CourseService courseService) {
|
|
|
this.courseDAO = courseDAO;
|
|
|
this.slideDAO = slideDAO;
|
|
|
this.chooseDAO = chooseDAO;
|
|
|
this.userDAO = userDAO;
|
|
|
- this.fileUtils = fileUtils;
|
|
|
- this.cacheUtils = cacheUtils;
|
|
|
- this.messageService = messageService;
|
|
|
+ this.ossUtils = ossUtils;
|
|
|
+ this.ossObjectUrlUtils = ossObjectUrlUtils;
|
|
|
this.quizService = quizService;
|
|
|
+ this.messageService = messageService;
|
|
|
this.courseService = courseService;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@SneakyThrows
|
|
|
@Override
|
|
|
public SlideVO createSlide(LoginUser teacher, SlideDTO slideDTO) {
|
|
|
Course course = courseDAO.findCourseById(slideDTO.getCourseId());
|
|
|
- AuthUtils.checkDataAuth(teacher.getId(), course.getTeacher().getId(), "您无权创建该课程的课件");
|
|
|
-
|
|
|
- checkSameName(0L, slideDTO.getCourseId(), slideDTO.getName());
|
|
|
|
|
|
Slide slide = new Slide()
|
|
|
.setCourse(course)
|
|
|
@@ -87,52 +80,53 @@ public class SlideServiceImpl implements SlideService {
|
|
|
.setName(slideDTO.getName())
|
|
|
.setState(slideDTO.getState());
|
|
|
|
|
|
- MultipartFile file = slideDTO.getFile();
|
|
|
- FileInfo fileInfo = getFileInfo(file);
|
|
|
- slide.setPages(fileInfo.pages);
|
|
|
- slide.setObjectName("temp");
|
|
|
- slide = slideDAO.save(slide);
|
|
|
+ if (!existsAddAuth(teacher, slide)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权创建该课件");
|
|
|
+ }
|
|
|
|
|
|
- String objectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
|
|
|
- slide.setObjectName(objectName);
|
|
|
- slide = slideDAO.save(slide);
|
|
|
+ try {
|
|
|
+ MultipartFile file = slideDTO.getFile();
|
|
|
+ FileInfo fileInfo = getFileInfo(file);
|
|
|
+ slide.setPages(fileInfo.getPages());
|
|
|
+ slide.setObjectName("temp");
|
|
|
+ slide = slideDAO.save(slide);
|
|
|
|
|
|
- fileUtils.upload(objectName, file.getInputStream());
|
|
|
+ String objectName = getObjectName(slide.getId(), slide.getName(), fileInfo.getExtension());
|
|
|
+ slide.setObjectName(objectName);
|
|
|
+ slide = slideDAO.save(slide);
|
|
|
|
|
|
- return new SlideVO(slide);
|
|
|
+ ossUtils.upload(objectName, file.getInputStream());
|
|
|
+
|
|
|
+ return new SlideVO(slide);
|
|
|
+ } catch (DataIntegrityViolationException e) {
|
|
|
+ throw HelperException.of(ExceptionType.CONFLICT, "创建失败,请检查课件信息是否正确且不与已有课件冲突");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@Override
|
|
|
public SlideVO modifySlide(LoginUser user, Long slideId, SlideDTO slideDTO) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- AuthUtils.checkDataAuth(user.getId(), slide.getTeacher().getId(), "您无权修改该课件");
|
|
|
-
|
|
|
- checkSameName(slide.getId(), slide.getCourse().getId(), slideDTO.getName());
|
|
|
|
|
|
- slide.setName(slideDTO.getName());
|
|
|
- String oldObjectName = slide.getObjectName();
|
|
|
- String newObjectName = getObjectName(slide.getId(), slide.getName(), oldObjectName.substring(oldObjectName.lastIndexOf('.') + 1));
|
|
|
- slide.setObjectName(newObjectName);
|
|
|
- slide = slideDAO.save(slide);
|
|
|
-
|
|
|
- if (!oldObjectName.equals(newObjectName)) {
|
|
|
- fileUtils.copy(oldObjectName, newObjectName);
|
|
|
- fileUtils.delete(oldObjectName);
|
|
|
+ if (!existsUpdateAuth(user, slide)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权修改该课件");
|
|
|
}
|
|
|
|
|
|
- return new SlideVO(slide);
|
|
|
- }
|
|
|
-
|
|
|
- private void checkSameName(Long slideId, Long courseId, String name) {
|
|
|
- long exists = slideDAO.count((Specification<Slide>) (root, query, cb) -> cb.and(
|
|
|
- cb.notEqual(root.get("id"), slideId),
|
|
|
- cb.equal(root.get("course").get("id"), courseId),
|
|
|
- cb.equal(root.get("deleteAt"), 0L),
|
|
|
- cb.equal(root.get("name"), name)));
|
|
|
-
|
|
|
- if (exists > 0) {
|
|
|
- throw HelperException.of(ExceptionType.CONFLICT, "该课件名已使用");
|
|
|
+ try {
|
|
|
+ slide.setName(slideDTO.getName());
|
|
|
+ String oldObjectName = slide.getObjectName();
|
|
|
+ String newObjectName = getObjectName(slide.getId(), slide.getName(), Files.getFileExtension(oldObjectName));
|
|
|
+ slide.setObjectName(newObjectName);
|
|
|
+ slide = slideDAO.save(slide);
|
|
|
+
|
|
|
+ if (!oldObjectName.equals(newObjectName)) {
|
|
|
+ ossUtils.copy(oldObjectName, newObjectName);
|
|
|
+ ossUtils.delete(oldObjectName);
|
|
|
+ }
|
|
|
+
|
|
|
+ return new SlideVO(slide);
|
|
|
+ } catch (DataIntegrityViolationException e) {
|
|
|
+ throw HelperException.of(ExceptionType.CONFLICT, "修改失败,请检查课件信息是否正确且不与已有课件冲突");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -140,7 +134,10 @@ public class SlideServiceImpl implements SlideService {
|
|
|
@Override
|
|
|
public void modifySlideState(LoginUser user, Long slideId, SlideStateDTO slideStateDTO) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- AuthUtils.checkDataAuth(user.getId(), slide.getTeacher().getId(), "您无权修改该课件状态");
|
|
|
+
|
|
|
+ if (!existsUpdateAuth(user, slide)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权修改该课件状态");
|
|
|
+ }
|
|
|
|
|
|
slide.setState(slideStateDTO.getState());
|
|
|
slide = slideDAO.save(slide);
|
|
|
@@ -148,7 +145,7 @@ public class SlideServiceImpl implements SlideService {
|
|
|
// 增加通知
|
|
|
if (slide.getState() == SlideState.IN_CLASS) {
|
|
|
Set<Long> studentIds = chooseDAO.findStudentIdsByCourseId(slide.getCourse().getId());
|
|
|
- messageService.createMessage(studentIds, MessageType.SLIDE_IN_CLASS, String.format(" [%s] - [%s] 已开课", slide.getCourse().getName(), slide.getName()), slide.getId());
|
|
|
+ messageService.createMessage(studentIds, MessageType.SLIDE_IN_CLASS, String.format("[%s] - [%s] 已开课", slide.getCourse().getName(), slide.getName()), slide.getId());
|
|
|
}
|
|
|
|
|
|
// 修改Slide状态同时推进quiz状态
|
|
|
@@ -160,20 +157,23 @@ public class SlideServiceImpl implements SlideService {
|
|
|
@Override
|
|
|
public void modifySlideFile(LoginUser user, Long slideId, SlideFileDTO slideFileDTO) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- AuthUtils.checkDataAuth(user.getId(), slide.getTeacher().getId(), "您无权修改该课件文件");
|
|
|
+
|
|
|
+ if (!existsUpdateAuth(user, slide)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权修改该课件文件");
|
|
|
+ }
|
|
|
|
|
|
MultipartFile file = slideFileDTO.getFile();
|
|
|
FileInfo fileInfo = getFileInfo(file);
|
|
|
- slide.setPages(fileInfo.pages);
|
|
|
+ slide.setPages(fileInfo.getPages());
|
|
|
|
|
|
String oldObjectName = slide.getObjectName();
|
|
|
- String newObjectName = getObjectName(slide.getId(), slide.getName(), fileInfo.suffix);
|
|
|
+ String newObjectName = getObjectName(slide.getId(), slide.getName(), fileInfo.getExtension());
|
|
|
slide.setObjectName(newObjectName);
|
|
|
slideDAO.save(slide);
|
|
|
|
|
|
- fileUtils.upload(newObjectName, file.getInputStream());
|
|
|
+ ossUtils.upload(newObjectName, file.getInputStream());
|
|
|
if (!oldObjectName.equals(newObjectName)) {
|
|
|
- fileUtils.delete(oldObjectName);
|
|
|
+ ossUtils.delete(oldObjectName);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -181,125 +181,93 @@ public class SlideServiceImpl implements SlideService {
|
|
|
@Override
|
|
|
public void deleteSlide(LoginUser user, Long slideId) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- AuthUtils.checkDataAuth(user.getId(), slide.getTeacher().getId(), "您无权删除该课件");
|
|
|
+
|
|
|
+ if (!existsDelAuth(user, slide)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权删除该课件");
|
|
|
+ }
|
|
|
|
|
|
slide.setDeleteAt(System.currentTimeMillis());
|
|
|
slideDAO.save(slide);
|
|
|
+ messageService.deleteMessages(slideId, MessageType.SLIDE_IN_CLASS);
|
|
|
}
|
|
|
|
|
|
- @SuppressWarnings("all")
|
|
|
@SneakyThrows
|
|
|
private FileInfo getFileInfo(MultipartFile file) {
|
|
|
- switch (Objects.requireNonNull(file.getContentType())) {
|
|
|
- case "application/pdf":
|
|
|
- // 解析页数
|
|
|
- PDDocument doc = PDDocument.load(file.getInputStream());
|
|
|
- return FileInfo.of(doc.getNumberOfPages(), "pdf");
|
|
|
- default:
|
|
|
- throw HelperException.of(ExceptionType.PARAM_ERROR, "不支持的文件类型");
|
|
|
- }
|
|
|
+ return FileUtils.getFileInfo(file);
|
|
|
}
|
|
|
|
|
|
- @AllArgsConstructor(staticName = "of")
|
|
|
- private static class FileInfo {
|
|
|
- private int pages;
|
|
|
- private String suffix;
|
|
|
- }
|
|
|
-
|
|
|
- private String getObjectName(Long slideId, String slideName, String suffix) {
|
|
|
- return SLIDE_STORE_DIR + File.separator + slideId + File.separator + slideName + "." + suffix;
|
|
|
+ private String getObjectName(Long slideId, String slideName, String extension) {
|
|
|
+ return SLIDE_STORE_DIR + File.separator + slideId + File.separator + slideName + "." + extension;
|
|
|
}
|
|
|
|
|
|
@Transactional(readOnly = true)
|
|
|
@Override
|
|
|
public Page<SlideVO> teacherGetSlides(LoginUser teacher, String key, Pageable pageable) {
|
|
|
- return findByTeacherIdAndKey(teacher.getId(), key, pageable).map(SlideVO::new);
|
|
|
+ return slideDAO.findByTeacherAndNameContains(userDAO.findUserById(teacher.getId()), key, pageable).map(SlideVO::new);
|
|
|
}
|
|
|
|
|
|
+ private static final Set<SlideState> STATES_NOT_GET_BY_STUDENT_SET = ImmutableSet.of(SlideState.DRAFT);
|
|
|
+
|
|
|
@Transactional(readOnly = true)
|
|
|
@Override
|
|
|
public Page<SlideVO> getSlidesByCourse(LoginUser user, Long courseId, String key, Pageable pageable) {
|
|
|
- if (!courseService.existsCourseResourcesGetAuth(user, courseId)) {
|
|
|
+ Course course = courseDAO.findCourseById(courseId);
|
|
|
+
|
|
|
+ if (!courseService.existsGetAuth(user, course)) {
|
|
|
throw HelperException.of(ExceptionType.FORBIDDEN, "您无权访问该课程的课件");
|
|
|
}
|
|
|
+
|
|
|
switch (user.getType()) {
|
|
|
case TEACHER:
|
|
|
- return teacherGetSlidesByCourse(courseId, key, pageable);
|
|
|
+ return slideDAO.findByCourseAndNameContains(course, key, pageable).map(SlideVO::new);
|
|
|
case STUDENT:
|
|
|
- return studentGetSlidesByCourse(courseId, key, pageable);
|
|
|
+ return slideDAO.findByCourseAndStateNotInAndNameContains(course, STATES_NOT_GET_BY_STUDENT_SET, key, pageable).map(SlideVO::new);
|
|
|
default:
|
|
|
return Page.empty();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private Page<SlideVO> teacherGetSlidesByCourse(Long courseId, String key, Pageable pageable) {
|
|
|
- return findByCourseIdAndKey(courseId, key, pageable).map(SlideVO::new);
|
|
|
- }
|
|
|
-
|
|
|
- private static final Set<SlideState> STATES_NOT_GET_BY_STUDENT_SET = ImmutableSet.of(SlideState.DRAFT);
|
|
|
-
|
|
|
- private Page<SlideVO> studentGetSlidesByCourse(Long courseId, String key, Pageable pageable) {
|
|
|
- return findByCourseIdAndKeyAndStateNotIn(courseId, STATES_NOT_GET_BY_STUDENT_SET, key, pageable).map(SlideVO::new);
|
|
|
- }
|
|
|
-
|
|
|
@Transactional(readOnly = true)
|
|
|
@Override
|
|
|
public String getSlideUrl(LoginUser user, Long slideId) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- if (!courseService.existsCourseResourcesGetAuth(user, slide.getCourse().getId())) {
|
|
|
+
|
|
|
+ if (!existsGetAuth(user, slide)) {
|
|
|
throw HelperException.of(ExceptionType.FORBIDDEN, "您无权获取该课件的链接");
|
|
|
}
|
|
|
|
|
|
- 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;
|
|
|
+ return ossObjectUrlUtils.getUrl(slide.getObjectName());
|
|
|
}
|
|
|
|
|
|
@Transactional(readOnly = true)
|
|
|
@Override
|
|
|
public SlideVO getOneSlide(LoginUser user, Long slideId) {
|
|
|
Slide slide = slideDAO.findSlideById(slideId);
|
|
|
- if (!courseService.existsCourseResourcesGetAuth(user, slide.getCourse().getId())) {
|
|
|
+
|
|
|
+ if (!existsGetAuth(user, slide)) {
|
|
|
throw HelperException.of(ExceptionType.FORBIDDEN, "您无权访问该课件");
|
|
|
}
|
|
|
+
|
|
|
return new SlideVO(slide);
|
|
|
}
|
|
|
|
|
|
- private Page<Slide> findByTeacherIdAndKey(Long teacherId, String key, Pageable pageable) {
|
|
|
- return slideDAO.findAll(
|
|
|
- (Specification<Slide>) (root, query, cb) -> cb.and(
|
|
|
- cb.equal(root.get("teacher").get("id"), teacherId)
|
|
|
- , cb.equal(root.get("deleteAt"), 0L)
|
|
|
- , cb.like(root.get("name"), StringUtils.keyPattern(key))
|
|
|
- , cb.equal(root.get("course").get("deleteAt"), 0L)
|
|
|
- ),
|
|
|
- pageable);
|
|
|
+ @Override
|
|
|
+ public boolean existsAddAuth(LoginUser user, Slide slide) {
|
|
|
+ return slide.getCourse().getTeacher().getId().equals(user.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean existsDelAuth(LoginUser user, Slide slide) {
|
|
|
+ return slide.getTeacher().getId().equals(user.getId());
|
|
|
}
|
|
|
|
|
|
- private Page<Slide> findByCourseIdAndKey(Long courseId, String key, Pageable pageable) {
|
|
|
- return slideDAO.findAll(
|
|
|
- (Specification<Slide>) (root, query, cb) -> cb.and(
|
|
|
- cb.equal(root.get("course").get("id"), courseId)
|
|
|
- , cb.equal(root.get("deleteAt"), 0L)
|
|
|
- , cb.like(root.get("name"), StringUtils.keyPattern(key))
|
|
|
- , cb.equal(root.get("course").get("deleteAt"), 0L)
|
|
|
- ),
|
|
|
- pageable);
|
|
|
+ @Override
|
|
|
+ public boolean existsUpdateAuth(LoginUser user, Slide slide) {
|
|
|
+ return slide.getTeacher().getId().equals(user.getId());
|
|
|
}
|
|
|
|
|
|
- private Page<Slide> findByCourseIdAndKeyAndStateNotIn(Long courseId, Set<SlideState> exclusiveStates, String key, Pageable pageable) {
|
|
|
- return slideDAO.findAll(
|
|
|
- (Specification<Slide>) (root, query, cb) -> cb.and(
|
|
|
- cb.equal(root.get("course").get("id"), courseId)
|
|
|
- , cb.equal(root.get("deleteAt"), 0L)
|
|
|
- , cb.like(root.get("name"), StringUtils.keyPattern(key))
|
|
|
- , cb.not(root.get("state").in(exclusiveStates))
|
|
|
- , cb.equal(root.get("course").get("deleteAt"), 0L)
|
|
|
- ),
|
|
|
- pageable);
|
|
|
+ @Override
|
|
|
+ public boolean existsGetAuth(LoginUser user, Slide slide) {
|
|
|
+ return courseService.existsGetAuth(user, courseDAO.findCourseById(slide.getCourse().getId()));
|
|
|
}
|
|
|
}
|