diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/TrainingTaskController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/TrainingTaskController.java new file mode 100644 index 0000000..b0c97af --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/TrainingTaskController.java @@ -0,0 +1,237 @@ +package com.sztzjy.linkCommerce.controller.stu; + +import com.alibaba.excel.EasyExcel; +import com.sztzjy.linkCommerce.config.exception.UnAuthorizedException; +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.config.security.TokenProvider; +import com.sztzjy.linkCommerce.entity.TrainingTask; +import com.sztzjy.linkCommerce.entity.importDto.TrainingTaskImportDTO; +import com.sztzjy.linkCommerce.service.TrainingTaskService; +import com.sztzjy.linkCommerce.util.ResultEntity; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +@Api(tags = "Training task management") +@RequestMapping("api/training-tasks") +@RestController +public class TrainingTaskController { + @Autowired + private TrainingTaskService trainingTaskService; + + @GetMapping + @ApiOperation("Training task list") + public ResultEntity> list(@RequestParam(required = false) String projectName, + @RequestParam(required = false) String taskName, + @RequestParam(required = false) Boolean enabledOnly, + HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + if (isStudent(user)) { + return new ResultEntity<>(HttpStatus.OK, "Query success", + trainingTaskService.listForStudent(user.getUserId(), enabledOnly)); + } + return new ResultEntity<>(HttpStatus.OK, "Query success", + trainingTaskService.listDefaults(projectName, taskName, enabledOnly)); + } + + @GetMapping("/{id}") + @ApiOperation("Training task detail") + public ResultEntity detail(@PathVariable String id, HttpServletRequest request) { + requireAdmin(request); + TrainingTask task = trainingTaskService.getById(id); + if (task == null) { + return new ResultEntity<>(HttpStatus.NOT_FOUND, "Training task not found"); + } + return new ResultEntity<>(HttpStatus.OK, "Query success", task); + } + + @GetMapping("/key/{taskKey}") + @ApiOperation("Training task detail by key") + public ResultEntity detailByTaskKey(@PathVariable String taskKey, HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + TrainingTask task = isStudent(user) + ? trainingTaskService.getStudentTaskByTaskKey(taskKey, user.getUserId()) + : trainingTaskService.getByTaskKey(taskKey); + if (task == null) { + return new ResultEntity<>(HttpStatus.OK, "Training task not configured", null); + } + return new ResultEntity<>(HttpStatus.OK, "Query success", task); + } + + @GetMapping("/classes/{teachingClassId}") + @ApiOperation("Training task list for teaching class") + public ResultEntity> listForTeachingClass(@PathVariable String teachingClassId, + @RequestParam(required = false) Boolean enabledOnly, + HttpServletRequest request) { + JwtUser user = requireTeacher(request); + try { + return new ResultEntity<>(HttpStatus.OK, "Query success", + trainingTaskService.listForTeachingClass(teachingClassId, enabledOnly, user.getUserId())); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @GetMapping("/classes/{teachingClassId}/key/{taskKey}") + @ApiOperation("Training task detail for teaching class by key") + public ResultEntity getClassTaskByTaskKey(@PathVariable String teachingClassId, + @PathVariable String taskKey, + HttpServletRequest request) { + JwtUser user = requireTeacher(request); + try { + TrainingTask task = trainingTaskService.getClassTaskByTaskKey(teachingClassId, taskKey, user.getUserId()); + if (task == null) { + return new ResultEntity<>(HttpStatus.OK, "Training task not configured", null); + } + return new ResultEntity<>(HttpStatus.OK, "Query success", task); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @PutMapping("/classes/{teachingClassId}/{taskKey}") + @ApiOperation("Save training task for teaching class") + public ResultEntity saveClassTask(@PathVariable String teachingClassId, + @PathVariable String taskKey, + @RequestBody TrainingTask task, + HttpServletRequest request) { + JwtUser user = requireTeacher(request); + try { + return new ResultEntity<>(HttpStatus.OK, "Save success", + trainingTaskService.saveClassTask(teachingClassId, taskKey, task, user.getUserId())); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @PostMapping + @ApiOperation("Create training task") + public ResultEntity create(@RequestBody TrainingTask task, HttpServletRequest request) { + JwtUser user = requireAdmin(request); + try { + return new ResultEntity<>(HttpStatus.OK, "Create success", trainingTaskService.create(task, user.getUserId())); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @PutMapping("/{id}") + @ApiOperation("Update training task") + public ResultEntity update(@PathVariable String id, + @RequestBody TrainingTask task, + HttpServletRequest request) { + requireAdmin(request); + if (trainingTaskService.getById(id) == null) { + return new ResultEntity<>(HttpStatus.NOT_FOUND, "Training task not found"); + } + try { + return new ResultEntity<>(HttpStatus.OK, "Update success", trainingTaskService.update(id, task)); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @DeleteMapping("/{id}") + @ApiOperation("Delete training task") + public ResultEntity delete(@PathVariable String id, HttpServletRequest request) { + requireAdmin(request); + if (trainingTaskService.getById(id) == null) { + return new ResultEntity<>(HttpStatus.NOT_FOUND, "Training task not found"); + } + try { + trainingTaskService.delete(id); + return new ResultEntity<>(HttpStatus.OK, "Delete success"); + } catch (IllegalArgumentException e) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } + } + + @PostMapping("/import") + @ApiOperation("Import training tasks") + @Transactional(rollbackFor = Exception.class) + public ResultEntity importTasks(@RequestParam("file") MultipartFile file, HttpServletRequest request) { + JwtUser user = requireAdmin(request); + ResultEntity fileError = validateImportFile(file); + if (fileError != null) { + return fileError; + } + + try (InputStream inputStream = file.getInputStream()) { + List rows = EasyExcel.read(inputStream) + .head(TrainingTaskImportDTO.class) + .sheet() + .doReadSync(); + List errors = new ArrayList<>(); + int count = trainingTaskService.importTasks(rows, user.getUserId(), errors); + if (!errors.isEmpty()) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "Data validation failed", errors); + } + return new ResultEntity<>(HttpStatus.OK, "Import success, total " + count + " rows"); + } catch (IllegalArgumentException e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return new ResultEntity<>(HttpStatus.BAD_REQUEST, e.getMessage()); + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return new ResultEntity<>(HttpStatus.ACCEPTED, "Import failed: " + e.getMessage()); + } + } + + @GetMapping("/template") + @ApiOperation("Download training task import template") + public void downloadTemplate(HttpServletRequest request, HttpServletResponse response) throws Exception { + requireAdmin(request); + String filename = URLEncoder.encode("training-task-import-template.xlsx", StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20"); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + filename); + EasyExcel.write(response.getOutputStream(), TrainingTaskImportDTO.class) + .sheet("training-tasks") + .doWrite(trainingTaskService.templateRows()); + } + + private boolean isStudent(JwtUser user) { + return user != null && user.getRoleId() == 4; + } + + private JwtUser requireAdmin(HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + if (user == null || user.getRoleId() != 1) { + throw new UnAuthorizedException("Admin only"); + } + return user; + } + + private JwtUser requireTeacher(HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + if (user == null || (user.getRoleId() != 1 && user.getRoleId() != 3)) { + throw new UnAuthorizedException("Teacher only"); + } + return user; + } + + private ResultEntity validateImportFile(MultipartFile file) { + if (file == null || file.isEmpty()) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "Please select an Excel file"); + } + String filename = StringUtils.defaultString(file.getOriginalFilename()); + if (!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx")) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "Only xls or xlsx files are supported"); + } + return null; + } +}