From 0dc1c0b76b2a948974c55ccb934c73c4d2156dde Mon Sep 17 00:00:00 2001 From: chenyuan Date: Sat, 1 Aug 2026 14:02:34 +0800 Subject: [PATCH] feat: lock teachers that own classes --- .../controller/stu/UserController.java | 44 ++++++++++++++-- .../sztzjy/linkCommerce/entity/Userinfo.java | 11 ++++ .../stu/UserControllerTeacherAdminTest.java | 50 +++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java index 0da6a72..446f7cb 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java @@ -621,7 +621,15 @@ public class UserController { @ApiParam("教师名称") @RequestParam(required = false) String name, @ApiParam("教师工号") @RequestParam(required = false) String userName, @RequestParam Integer index, - @RequestParam Integer size) { + @RequestParam Integer size, + @RequestParam(required = false) String operatorId) { + if (StringUtils.isNotBlank(operatorId)) { + Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); + if (!isSchoolTeacher(operator)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权查询教师账号信息"); + } + schoolId = operator.getSchoolId(); + } PageHelper.startPage(index, size); UserinfoExample userInfoExample = new UserinfoExample(); UserinfoExample.Criteria criteria = userInfoExample.createCriteria(); @@ -647,6 +655,7 @@ public class UserController { userInfoList.get(i).setSchoolName(school.getSchoolName()); } } + markTeachersWithCreatedClasses(userInfoList); PageInfo pageInfo = new PageInfo<>(userInfoList); return new ResultEntity<>(HttpStatus.OK, "查询教师账号信息成功!", pageInfo); } @@ -657,7 +666,13 @@ public class UserController { @AnonymousAccess public ResultEntity updateTeacher(@RequestBody Userinfo userInfo, @RequestParam(required = false) String operatorId) { Userinfo existing = userinfoMapper.selectByPrimaryKey(userInfo.getUserId()); - String schoolId = existing == null ? userInfo.getSchoolId() : existing.getSchoolId(); + if (existing == null || !Integer.valueOf(3).equals(existing.getRole())) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "教师账号不存在"); + } + if (teacherHasCreatedClass(existing.getUserId())) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该教师已创建班级,不允许编辑或删除"); + } + String schoolId = existing.getSchoolId(); if (!canManageSchoolStructure(operatorId, schoolId)) { return noManagePermission(); } @@ -707,7 +722,7 @@ public class UserController { return noManagePermission(); } if (teacherHasCreatedClass(userId)) { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该教师已创建班级,不能删除"); + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该教师已创建班级,不允许编辑或删除"); } int i = userinfoMapper.deleteByPrimaryKey(userId); if (i == 1) { @@ -2227,7 +2242,28 @@ public class UserController { private boolean teacherHasCreatedClass(String teacherId) { SchoolClassExample example = new SchoolClassExample(); example.createCriteria().andCreatedByEqualTo(teacherId); - return !schoolClassMapper.selectByExample(example).isEmpty(); + List classes = schoolClassMapper.selectByExample(example); + return classes != null && !classes.isEmpty(); + } + + private void markTeachersWithCreatedClasses(List teachers) { + if (teachers == null || teachers.isEmpty()) { + return; + } + List teacherIds = teachers.stream() + .map(Userinfo::getUserId) + .filter(StringUtils::isNotBlank) + .collect(java.util.stream.Collectors.toList()); + if (teacherIds.isEmpty()) { + return; + } + SchoolClassExample example = new SchoolClassExample(); + example.createCriteria().andCreatedByIn(teacherIds); + Set classOwnerIds = schoolClassMapper.selectByExample(example).stream() + .map(SchoolClass::getCreatedBy) + .filter(StringUtils::isNotBlank) + .collect(java.util.stream.Collectors.toSet()); + teachers.forEach(teacher -> teacher.setHasCreatedClass(classOwnerIds.contains(teacher.getUserId()))); } private boolean canOperateClass(String operatorId, String schoolClassId) { diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/Userinfo.java b/src/main/java/com/sztzjy/linkCommerce/entity/Userinfo.java index 05d78ed..28c1342 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/Userinfo.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/Userinfo.java @@ -80,6 +80,9 @@ public class Userinfo { @ApiModelProperty("学校名称 回显用") private String schoolName; + @ApiModelProperty("是否已创建班级,教师管理列表展示用") + private Boolean hasCreatedClass = false; + public String getClassName() { return className; } @@ -96,6 +99,14 @@ public class Userinfo { this.schoolName = schoolName; } + public Boolean getHasCreatedClass() { + return hasCreatedClass; + } + + public void setHasCreatedClass(Boolean hasCreatedClass) { + this.hasCreatedClass = hasCreatedClass; + } + public String getUserId() { return userId; } diff --git a/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java b/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java index be7299a..ba2c108 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java @@ -7,6 +7,7 @@ import com.sztzjy.linkCommerce.entity.SchoolFaculty; import com.sztzjy.linkCommerce.entity.SchoolMajor; import com.sztzjy.linkCommerce.entity.TeachingClassStudent; import com.sztzjy.linkCommerce.entity.Userinfo; +import com.sztzjy.linkCommerce.entity.UserinfoExample; import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; import com.sztzjy.linkCommerce.mapper.SchoolFacultyMapper; import com.sztzjy.linkCommerce.mapper.SchoolMapper; @@ -31,6 +32,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; @@ -118,6 +120,48 @@ class UserControllerTeacherAdminTest { verify(controller.userinfoMapper, never()).updateByPrimaryKey(any(Userinfo.class)); } + @Test + void teacherManagementListsCurrentSchoolTeachersAndMarksClassOwners() { + UserController controller = controllerWithCommonMocks(); + Userinfo owner = teacher("teacher-owner"); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-admin")).thenReturn(teacher("teacher-admin", true)); + when(controller.userinfoMapper.selectByExample(any(UserinfoExample.class))).thenReturn(Collections.singletonList(owner)); + when(controller.schoolClassMapper.selectByExample(any(SchoolClassExample.class))).thenReturn(Collections.singletonList(classCreatedBy("teacher-owner"))); + + ResultEntity> result = controller.selectTeacher(null, null, null, 1, 10, "teacher-admin"); + + ArgumentCaptor exampleCaptor = ArgumentCaptor.forClass(UserinfoExample.class); + verify(controller.userinfoMapper).selectByExample(exampleCaptor.capture()); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertTrue(hasUserCondition(exampleCaptor.getValue(), "school_id =", "school-1")); + assertTrue(result.getBody().getData().getList().get(0).getHasCreatedClass()); + } + + @Test + void managerTeacherCannotUpdateTeacherWhoCreatedAClass() { + UserController controller = controllerWithCommonMocks(); + Userinfo owner = teacher("teacher-owner"); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-owner")).thenReturn(owner); + when(controller.schoolClassMapper.selectByExample(any(SchoolClassExample.class))).thenReturn(Collections.singletonList(classCreatedBy("teacher-owner"))); + + ResultEntity result = controller.updateTeacher(owner, "teacher-admin"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.userinfoMapper, never()).updateByPrimaryKey(any(Userinfo.class)); + } + + @Test + void managerTeacherCannotDeleteTeacherWhoCreatedAClass() { + UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-owner")).thenReturn(teacher("teacher-owner")); + when(controller.schoolClassMapper.selectByExample(any(SchoolClassExample.class))).thenReturn(Collections.singletonList(classCreatedBy("teacher-owner"))); + + ResultEntity result = controller.deleteTeacher("teacher-owner", "teacher-admin"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.userinfoMapper, never()).deleteByPrimaryKey("teacher-owner"); + } + @Test void addSchoolClassStoresCreatorTeacher() { UserController controller = controllerWithCommonMocks(); @@ -1138,6 +1182,12 @@ class UserControllerTeacherAdminTest { .anyMatch(criterion -> condition.equals(criterion.getCondition())); } + private boolean hasUserCondition(UserinfoExample example, String condition, Object value) { + return example.getOredCriteria().stream() + .flatMap(criteria -> criteria.getAllCriteria().stream()) + .anyMatch(criterion -> condition.equals(criterion.getCondition()) && value.equals(criterion.getValue())); + } + private TeachingClassStudentImportDTO teachingClassStudentRow(String studentName, String userName) { TeachingClassStudentImportDTO row = new TeachingClassStudentImportDTO(); row.setStudentName(studentName);