|
|
@@ -0,0 +1,134 @@
|
|
|
+package nju.seec.helper.service.impl;
|
|
|
+
|
|
|
+import lombok.SneakyThrows;
|
|
|
+import nju.seec.helper.dao.ChooseDAO;
|
|
|
+import nju.seec.helper.dao.CourseDAO;
|
|
|
+import nju.seec.helper.dao.CourseFileDAO;
|
|
|
+import nju.seec.helper.dto.CourseFileDTO;
|
|
|
+import nju.seec.helper.dto.LoginUser;
|
|
|
+import nju.seec.helper.entity.Course;
|
|
|
+import nju.seec.helper.entity.CourseFile;
|
|
|
+import nju.seec.helper.service.CourseFileService;
|
|
|
+import nju.seec.helper.service.util.AuthUtils;
|
|
|
+import nju.seec.helper.util.CacheUtils;
|
|
|
+import nju.seec.helper.util.Consts;
|
|
|
+import nju.seec.helper.util.FileUtils;
|
|
|
+import nju.seec.helper.util.enums.ExceptionType;
|
|
|
+import nju.seec.helper.util.exception.HelperException;
|
|
|
+import nju.seec.helper.vo.CourseFileVO;
|
|
|
+import org.springframework.data.domain.Page;
|
|
|
+import org.springframework.data.domain.Pageable;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author cst
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class CourseFileServiceImpl implements CourseFileService {
|
|
|
+ private static final String COURSE_FILE_STORE_DIR = "course_file";
|
|
|
+ private static final long COURSE_FILE_URL_LIVING_SECONDS = 20 * 60;
|
|
|
+
|
|
|
+ private final CourseDAO courseDAO;
|
|
|
+ private final CourseFileDAO courseFileDAO;
|
|
|
+ private final ChooseDAO chooseDAO;
|
|
|
+
|
|
|
+
|
|
|
+ private final FileUtils fileUtils;
|
|
|
+ private final CacheUtils cacheUtils;
|
|
|
+
|
|
|
+ public CourseFileServiceImpl(CourseDAO courseDAO, CourseFileDAO courseFileDAO, ChooseDAO chooseDAO, FileUtils fileUtils, CacheUtils cacheUtils) {
|
|
|
+ this.courseDAO = courseDAO;
|
|
|
+ this.courseFileDAO = courseFileDAO;
|
|
|
+ this.chooseDAO = chooseDAO;
|
|
|
+ this.fileUtils = fileUtils;
|
|
|
+ this.cacheUtils = cacheUtils;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @SneakyThrows
|
|
|
+ @Override
|
|
|
+ public void uploadCourseFile(LoginUser user, CourseFileDTO courseFileDTO) {
|
|
|
+ Course course = courseDAO.findCourseById(courseFileDTO.getCourseId());
|
|
|
+ AuthUtils.checkDataAuth(user.getId(), course.getTeacher().getId(), "您无权上传该课程的附件");
|
|
|
+
|
|
|
+ MultipartFile file = courseFileDTO.getFile();
|
|
|
+ String fileName = file.getOriginalFilename();
|
|
|
+
|
|
|
+ if (courseFileDAO.existsByCourseIdAndFileName(courseFileDTO.getCourseId(), fileName)) {
|
|
|
+ throw HelperException.of(ExceptionType.CONFLICT, "已有同名附件");
|
|
|
+ }
|
|
|
+
|
|
|
+ String objectName = getCourseFileObjectName(course.getId(), fileName);
|
|
|
+
|
|
|
+ CourseFile courseFile = new CourseFile()
|
|
|
+ .setCourseId(course.getId())
|
|
|
+ .setTeacherId(user.getId())
|
|
|
+ .setFileName(file.getOriginalFilename())
|
|
|
+ .setObjectName(objectName);
|
|
|
+
|
|
|
+ courseFileDAO.save(courseFile);
|
|
|
+
|
|
|
+ fileUtils.upload(objectName, file.getInputStream());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @Override
|
|
|
+ public void deleteCourseFile(LoginUser user, Long courseFileId) {
|
|
|
+ CourseFile courseFile = courseFileDAO.findCourseFileById(courseFileId);
|
|
|
+ AuthUtils.checkDataAuth(user.getId(), courseFile.getTeacherId(), "您无权删除该附件");
|
|
|
+ courseFileDAO.deleteById(courseFileId);
|
|
|
+ fileUtils.delete(courseFile.getObjectName());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(readOnly = true)
|
|
|
+ @Override
|
|
|
+ public Page<CourseFileVO> getCourseFiles(LoginUser user, Long courseId, String key, Pageable pageable) {
|
|
|
+ if (!chooseDAO.existsByStudentIdAndCourseId(user.getId(), courseId)) {
|
|
|
+ throw HelperException.of(ExceptionType.FORBIDDEN, "您无权查看该课程的附件");
|
|
|
+ }
|
|
|
+ return courseFileDAO.findByCourseIdAndFileNameContains(courseId, key, pageable).map(CourseFileVO::new);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(readOnly = true)
|
|
|
+ @Override
|
|
|
+ public String getCourseFileUrl(LoginUser user, Long courseFileId) {
|
|
|
+ CourseFile courseFile = courseFileDAO.findCourseFileById(courseFileId);
|
|
|
+ checkDataAccessAuth(user, courseFile);
|
|
|
+
|
|
|
+ String url = cacheUtils.get(Consts.COURSE_FILE_URL_CACHE_NAME, courseFile.getObjectName());
|
|
|
+ if (url != null) {
|
|
|
+ return url;
|
|
|
+ }
|
|
|
+ url = fileUtils.getUrl(courseFile.getObjectName(), COURSE_FILE_URL_LIVING_SECONDS);
|
|
|
+ cacheUtils.set(Consts.COURSE_FILE_URL_CACHE_NAME, courseFile.getObjectName(), url, COURSE_FILE_URL_LIVING_SECONDS, TimeUnit.SECONDS);
|
|
|
+ return url;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getCourseFileObjectName(Long courseId, String fileName) {
|
|
|
+ return COURSE_FILE_STORE_DIR + File.separator + courseId + File.separator + fileName;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void checkDataAccessAuth(LoginUser user, CourseFile courseFile) {
|
|
|
+ HelperException forbiddenEx = HelperException.of(ExceptionType.FORBIDDEN, "您无权访问该附件");
|
|
|
+
|
|
|
+ switch (user.getType()) {
|
|
|
+ case TEACHER:
|
|
|
+ if (!courseFile.getTeacherId().equals(user.getId())) {
|
|
|
+ throw forbiddenEx;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case STUDENT:
|
|
|
+ if (!chooseDAO.existsByStudentIdAndCourseId(user.getId(), courseFile.getCourseId())) {
|
|
|
+ throw forbiddenEx;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw forbiddenEx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|