feat: enforce organization mode boundaries

main
chenyuan 1 month ago
parent e4c5093466
commit 8e4e5b6ac7

@ -12,6 +12,7 @@ import com.sztzjy.linkCommerce.entity.dto.SchoolMajorDto;
import com.sztzjy.linkCommerce.entity.importDto.SchoolAdminStudentImportDTO; import com.sztzjy.linkCommerce.entity.importDto.SchoolAdminStudentImportDTO;
import com.sztzjy.linkCommerce.mapper.*; import com.sztzjy.linkCommerce.mapper.*;
import com.sztzjy.linkCommerce.service.SchoolAdminService; import com.sztzjy.linkCommerce.service.SchoolAdminService;
import com.sztzjy.linkCommerce.service.SchoolProductConfigService;
import com.sztzjy.linkCommerce.service.SchoolService; import com.sztzjy.linkCommerce.service.SchoolService;
import com.sztzjy.linkCommerce.service.UserInfoService; import com.sztzjy.linkCommerce.service.UserInfoService;
import com.sztzjy.linkCommerce.util.ResultEntity; import com.sztzjy.linkCommerce.util.ResultEntity;
@ -56,6 +57,8 @@ public class SchoolAdminController {
private UserinfoMapper userinfoMapper; private UserinfoMapper userinfoMapper;
@Autowired @Autowired
private TaskAllocationMapper taskAllocationMapper; private TaskAllocationMapper taskAllocationMapper;
@Autowired
private SchoolProductConfigService schoolProductConfigService;
@GetMapping("/school") @GetMapping("/school")
@ApiOperation("学校管理员-当前学校详情") @ApiOperation("学校管理员-当前学校详情")
@ -81,6 +84,7 @@ public class SchoolAdminController {
@RequestParam(required = false) String schoolFacultyName, @RequestParam(required = false) String schoolFacultyName,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
PageInfo<SchoolFacultyDto> pageInfo = schoolService.seleteSchoolFaculty(index, size, schoolId, schoolFacultyName); PageInfo<SchoolFacultyDto> pageInfo = schoolService.seleteSchoolFaculty(index, size, schoolId, schoolFacultyName);
return new ResultEntity<>(HttpStatus.OK, "查询成功", pageInfo); return new ResultEntity<>(HttpStatus.OK, "查询成功", pageInfo);
} }
@ -89,6 +93,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-新增院系") @ApiOperation("学校管理员-新增院系")
public ResultEntity addFaculty(@RequestBody SchoolFaculty faculty, HttpServletRequest request) { public ResultEntity addFaculty(@RequestBody SchoolFaculty faculty, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isBlank(faculty.getSchoolFacultyName())) { if (StringUtils.isBlank(faculty.getSchoolFacultyName())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系名称不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系名称不能为空");
} }
@ -105,6 +110,7 @@ public class SchoolAdminController {
@RequestBody SchoolFaculty faculty, @RequestBody SchoolFaculty faculty,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
SchoolFaculty existing = requireFaculty(id, schoolId); SchoolFaculty existing = requireFaculty(id, schoolId);
faculty.setSchoolFacultyId(existing.getSchoolFacultyId()); faculty.setSchoolFacultyId(existing.getSchoolFacultyId());
faculty.setSchoolId(schoolId); faculty.setSchoolId(schoolId);
@ -116,6 +122,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-删除院系") @ApiOperation("学校管理员-删除院系")
public ResultEntity deleteFaculty(@PathVariable String id, HttpServletRequest request) { public ResultEntity deleteFaculty(@PathVariable String id, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireFaculty(id, schoolId); requireFaculty(id, schoolId);
if (hasMajorInFaculty(id) || hasUserByFaculty(id)) { if (hasMajorInFaculty(id) || hasUserByFaculty(id)) {
return new ResultEntity<>(HttpStatus.ACCEPTED, "院系下存在专业或用户,不能删除"); return new ResultEntity<>(HttpStatus.ACCEPTED, "院系下存在专业或用户,不能删除");
@ -132,6 +139,7 @@ public class SchoolAdminController {
@RequestParam(required = false) String schoolFacultyId, @RequestParam(required = false) String schoolFacultyId,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isNotBlank(schoolFacultyId)) { if (StringUtils.isNotBlank(schoolFacultyId)) {
requireFaculty(schoolFacultyId, schoolId); requireFaculty(schoolFacultyId, schoolId);
} }
@ -143,6 +151,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-新增专业") @ApiOperation("学校管理员-新增专业")
public ResultEntity addMajor(@RequestBody SchoolMajor major, HttpServletRequest request) { public ResultEntity addMajor(@RequestBody SchoolMajor major, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isBlank(major.getSchoolMajorName())) { if (StringUtils.isBlank(major.getSchoolMajorName())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "专业名称不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "专业名称不能为空");
} }
@ -159,6 +168,7 @@ public class SchoolAdminController {
@RequestBody SchoolMajor major, @RequestBody SchoolMajor major,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireMajor(id, schoolId); requireMajor(id, schoolId);
if (StringUtils.isNotBlank(major.getSchoolFacultyId())) { if (StringUtils.isNotBlank(major.getSchoolFacultyId())) {
requireFaculty(major.getSchoolFacultyId(), schoolId); requireFaculty(major.getSchoolFacultyId(), schoolId);
@ -172,6 +182,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-删除专业") @ApiOperation("学校管理员-删除专业")
public ResultEntity deleteMajor(@PathVariable String id, HttpServletRequest request) { public ResultEntity deleteMajor(@PathVariable String id, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireMajor(id, schoolId); requireMajor(id, schoolId);
if (hasClassInMajor(id) || hasUserByMajor(id)) { if (hasClassInMajor(id) || hasUserByMajor(id)) {
return new ResultEntity<>(HttpStatus.ACCEPTED, "专业下存在班级或用户,不能删除"); return new ResultEntity<>(HttpStatus.ACCEPTED, "专业下存在班级或用户,不能删除");
@ -189,6 +200,7 @@ public class SchoolAdminController {
@RequestParam(required = false) String schoolMajorId, @RequestParam(required = false) String schoolMajorId,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isNotBlank(schoolMajorId)) { if (StringUtils.isNotBlank(schoolMajorId)) {
requireMajor(schoolMajorId, schoolId); requireMajor(schoolMajorId, schoolId);
} }
@ -200,6 +212,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-新增班级") @ApiOperation("学校管理员-新增班级")
public ResultEntity addClass(@RequestBody SchoolClass schoolClass, HttpServletRequest request) { public ResultEntity addClass(@RequestBody SchoolClass schoolClass, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isBlank(schoolClass.getClassName())) { if (StringUtils.isBlank(schoolClass.getClassName())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级名称不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级名称不能为空");
} }
@ -217,6 +230,7 @@ public class SchoolAdminController {
@RequestBody SchoolClass schoolClass, @RequestBody SchoolClass schoolClass,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireClass(id, schoolId); requireClass(id, schoolId);
if (StringUtils.isNotBlank(schoolClass.getSchoolMajorId())) { if (StringUtils.isNotBlank(schoolClass.getSchoolMajorId())) {
requireMajor(schoolClass.getSchoolMajorId(), schoolId); requireMajor(schoolClass.getSchoolMajorId(), schoolId);
@ -231,6 +245,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-删除班级") @ApiOperation("学校管理员-删除班级")
public ResultEntity deleteClass(@PathVariable String id, HttpServletRequest request) { public ResultEntity deleteClass(@PathVariable String id, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireClass(id, schoolId); requireClass(id, schoolId);
if (hasStudentInClass(id) || hasTaskInClass(id, schoolId)) { if (hasStudentInClass(id) || hasTaskInClass(id, schoolId)) {
return new ResultEntity<>(HttpStatus.ACCEPTED, "班级下存在学生或任务,不能删除"); return new ResultEntity<>(HttpStatus.ACCEPTED, "班级下存在学生或任务,不能删除");
@ -302,6 +317,7 @@ public class SchoolAdminController {
@RequestParam(required = false) String schoolClassId, @RequestParam(required = false) String schoolClassId,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isNotBlank(schoolClassId)) { if (StringUtils.isNotBlank(schoolClassId)) {
requireClass(schoolClassId, schoolId); requireClass(schoolClassId, schoolId);
} }
@ -313,6 +329,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-新增学生") @ApiOperation("学校管理员-新增学生")
public ResultEntity addStudent(@RequestBody Userinfo student, HttpServletRequest request) { public ResultEntity addStudent(@RequestBody Userinfo student, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
if (StringUtils.isBlank(student.getUsername()) || StringUtils.isBlank(student.getName())) { if (StringUtils.isBlank(student.getUsername()) || StringUtils.isBlank(student.getName())) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空");
} }
@ -337,6 +354,7 @@ public class SchoolAdminController {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResultEntity importStudents(@RequestParam("file") MultipartFile file, HttpServletRequest request) { public ResultEntity importStudents(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
ResultEntity fileError = validateImportFile(file); ResultEntity fileError = validateImportFile(file);
if (fileError != null) { if (fileError != null) {
return fileError; return fileError;
@ -377,6 +395,7 @@ public class SchoolAdminController {
@RequestBody Userinfo student, @RequestBody Userinfo student,
HttpServletRequest request) { HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireUser(id, schoolId, 4); requireUser(id, schoolId, 4);
if (StringUtils.isNotBlank(student.getSchoolClassId())) { if (StringUtils.isNotBlank(student.getSchoolClassId())) {
requireClass(student.getSchoolClassId(), schoolId); requireClass(student.getSchoolClassId(), schoolId);
@ -391,6 +410,7 @@ public class SchoolAdminController {
@ApiOperation("学校管理员-删除学生") @ApiOperation("学校管理员-删除学生")
public ResultEntity deleteStudent(@PathVariable String id, HttpServletRequest request) { public ResultEntity deleteStudent(@PathVariable String id, HttpServletRequest request) {
String schoolId = currentSchoolId(request); String schoolId = currentSchoolId(request);
requireAdministrativeOrganization(schoolId);
requireUser(id, schoolId, 4); requireUser(id, schoolId, 4);
int count = userinfoMapper.deleteByPrimaryKey(id); int count = userinfoMapper.deleteByPrimaryKey(id);
return writeResult(count, "删除成功", "删除失败"); return writeResult(count, "删除成功", "删除失败");
@ -401,6 +421,10 @@ public class SchoolAdminController {
return schoolAdminService.requireSchoolAdmin(user); return schoolAdminService.requireSchoolAdmin(user);
} }
private void requireAdministrativeOrganization(String schoolId) {
schoolProductConfigService.requireAdminClassEnabled(schoolId);
}
private ResultEntity writeResult(int count, String success, String fail) { private ResultEntity writeResult(int count, String success, String fail) {
if (count > 0) { if (count > 0) {
return new ResultEntity<>(HttpStatus.OK, success); return new ResultEntity<>(HttpStatus.OK, success);

@ -1115,9 +1115,20 @@ public class UserController {
for (TeacherRosterStudentImportDTO row : rows) { for (TeacherRosterStudentImportDTO row : rows) {
String name = row == null ? "" : StringUtils.trimToEmpty(row.getName()); String name = row == null ? "" : StringUtils.trimToEmpty(row.getName());
String username = row == null ? "" : StringUtils.trimToEmpty(row.getUsername()); String username = row == null ? "" : StringUtils.trimToEmpty(row.getUsername());
if (StringUtils.isBlank(name) || StringUtils.isBlank(username) || userInfoService.existsByUserName(username)) { if (StringUtils.isBlank(name) || StringUtils.isBlank(username)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名或学号无效"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名或学号无效");
} }
Userinfo existingStudent = userinfoMapper.selectBySchoolIdAndUsername(operator.getSchoolId(), username);
if (existingStudent != null) {
if (!Integer.valueOf(4).equals(existingStudent.getRole()) || !StringUtils.equals(existingStudent.getName(), name)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学号与已有学生信息冲突");
}
upsertActiveTeachingClassMember(teachingClassId, existingStudent, null, "TEACHER_ROSTER_IMPORT");
continue;
}
if (userInfoService.existsByUserName(username)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学号已被其他学校使用");
}
Userinfo student = new Userinfo(); Userinfo student = new Userinfo();
student.setUserId(UUID.randomUUID().toString()); student.setUserId(UUID.randomUUID().toString());
student.setName(name); student.setName(name);
@ -1545,7 +1556,6 @@ public class UserController {
|| StringUtils.isBlank(student.getUserId())) { || StringUtils.isBlank(student.getUserId())) {
return; return;
} }
teachingClassStudentMapper.exitActiveByStudentUserIdExceptClass(student.getUserId(), teachingClassId);
TeachingClassStudent existing = teachingClassStudentMapper TeachingClassStudent existing = teachingClassStudentMapper
.selectByStudentUserIdAndTeachingClassId(student.getUserId(), teachingClassId); .selectByStudentUserIdAndTeachingClassId(student.getUserId(), teachingClassId);
if (existing != null) { if (existing != null) {

@ -24,6 +24,8 @@ public interface UserinfoMapper {
Userinfo selectByPrimaryKey(String userId); Userinfo selectByPrimaryKey(String userId);
Userinfo selectBySchoolIdAndUsername(@Param("schoolId") String schoolId, @Param("username") String username);
int updateByExampleSelective(@Param("record") Userinfo record, @Param("example") UserinfoExample example); int updateByExampleSelective(@Param("record") Userinfo record, @Param("example") UserinfoExample example);
int updateByExample(@Param("record") Userinfo record, @Param("example") UserinfoExample example); int updateByExample(@Param("record") Userinfo record, @Param("example") UserinfoExample example);

@ -1,8 +1,12 @@
package com.sztzjy.linkCommerce.service.impl; package com.sztzjy.linkCommerce.service.impl;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.entity.SchoolClassExample;
import com.sztzjy.linkCommerce.entity.SchoolProductConfig; import com.sztzjy.linkCommerce.entity.SchoolProductConfig;
import com.sztzjy.linkCommerce.entity.UserinfoExample;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.SchoolProductConfigMapper; import com.sztzjy.linkCommerce.mapper.SchoolProductConfigMapper;
import com.sztzjy.linkCommerce.mapper.UserinfoMapper;
import com.sztzjy.linkCommerce.service.SchoolProductConfigService; import com.sztzjy.linkCommerce.service.SchoolProductConfigService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -21,6 +25,12 @@ public class SchoolProductConfigServiceImpl implements SchoolProductConfigServic
@Autowired @Autowired
public SchoolProductConfigMapper schoolProductConfigMapper; public SchoolProductConfigMapper schoolProductConfigMapper;
@Autowired
public SchoolClassMapper schoolClassMapper;
@Autowired
public UserinfoMapper userinfoMapper;
@Override @Override
public void createDefaultConfig(String schoolId) { public void createDefaultConfig(String schoolId) {
if (StringUtils.isBlank(schoolId)) { if (StringUtils.isBlank(schoolId)) {
@ -45,7 +55,11 @@ public class SchoolProductConfigServiceImpl implements SchoolProductConfigServic
if (!standard && !teacherManaged) { if (!standard && !teacherManaged) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "学校组织模式与名单维护方不匹配"); throw new ServiceException(HttpStatus.BAD_REQUEST, "学校组织模式与名单维护方不匹配");
} }
getRequiredConfig(config.getSchoolId()); SchoolProductConfig current = getRequiredConfig(config.getSchoolId());
if (!StringUtils.equals(current.getOrganizationMode(), config.getOrganizationMode())
&& hasAdministrativeOrganizationData(config.getSchoolId())) {
throw new ServiceException(HttpStatus.BAD_REQUEST, "学校已有组织数据,不能直接切换组织模式");
}
config.setUpdateTime(new Date()); config.setUpdateTime(new Date());
schoolProductConfigMapper.updateByPrimaryKey(config); schoolProductConfigMapper.updateByPrimaryKey(config);
return getRequiredConfig(config.getSchoolId()); return getRequiredConfig(config.getSchoolId());
@ -79,4 +93,19 @@ public class SchoolProductConfigServiceImpl implements SchoolProductConfigServic
throw new ServiceException(HttpStatus.BAD_REQUEST, "当前学校未启用行政班"); throw new ServiceException(HttpStatus.BAD_REQUEST, "当前学校未启用行政班");
} }
} }
private boolean hasAdministrativeOrganizationData(String schoolId) {
SchoolClassExample classExample = new SchoolClassExample();
classExample.createCriteria()
.andSchoolIdEqualTo(schoolId)
.andClassTypeEqualTo("ADMIN");
if (schoolClassMapper.countByExample(classExample) > 0) {
return true;
}
UserinfoExample userExample = new UserinfoExample();
userExample.createCriteria()
.andSchoolIdEqualTo(schoolId)
.andSchoolClassIdIsNotNull();
return userinfoMapper.countByExample(userExample) > 0;
}
} }

@ -107,6 +107,12 @@
from userinfo from userinfo
where user_id = #{userId,jdbcType=VARCHAR} where user_id = #{userId,jdbcType=VARCHAR}
</select> </select>
<select id="selectBySchoolIdAndUsername" resultMap="BaseResultMap">
select <include refid="Base_Column_List" /> from userinfo
where school_id = #{schoolId,jdbcType=VARCHAR}
and username = #{username,jdbcType=VARCHAR}
limit 1
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String"> <delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from userinfo delete from userinfo
where user_id = #{userId,jdbcType=VARCHAR} where user_id = #{userId,jdbcType=VARCHAR}

@ -1,11 +1,15 @@
package com.sztzjy.linkCommerce.controller.schooladmin; package com.sztzjy.linkCommerce.controller.schooladmin;
import com.sztzjy.linkCommerce.service.SchoolProductConfigService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import java.util.Arrays; import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
class SchoolAdminControllerTest { class SchoolAdminControllerTest {
@ -18,4 +22,15 @@ class SchoolAdminControllerTest {
assertTrue(exists, "School admin student import must use /api/school-admin/students/import"); assertTrue(exists, "School admin student import must use /api/school-admin/students/import");
} }
@Test
void administrativeOrganizationGuardDelegatesToSchoolConfiguration() {
SchoolAdminController controller = new SchoolAdminController();
SchoolProductConfigService configService = mock(SchoolProductConfigService.class);
ReflectionTestUtils.setField(controller, "schoolProductConfigService", configService);
ReflectionTestUtils.invokeMethod(controller, "requireAdministrativeOrganization", "school-zj");
verify(configService).requireAdminClassEnabled("school-zj");
}
} }

@ -22,6 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -68,5 +69,33 @@ class TeacherRosterImportTest {
verify(controller.teachingClassStudentMapper).insertSelective(membership.capture()); verify(controller.teachingClassStudentMapper).insertSelective(membership.capture());
assertEquals("teach-1", membership.getValue().getTeachingClassId()); assertEquals("teach-1", membership.getValue().getTeachingClassId());
assertEquals(null, membership.getValue().getAdminClassId()); assertEquals(null, membership.getValue().getAdminClassId());
verify(controller.teachingClassStudentMapper, never())
.exitActiveByStudentUserIdExceptClass(org.mockito.ArgumentMatchers.anyString(), org.mockito.ArgumentMatchers.anyString());
}
@Test
void teacherRosterImportReusesExistingStudentInTheSameSchool() {
UserController controller = new UserController();
controller.userinfoMapper = mock(UserinfoMapper.class);
controller.schoolClassMapper = mock(SchoolClassMapper.class);
controller.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class);
controller.schoolProductConfigService = mock(SchoolProductConfigService.class);
Userinfo teacher = new Userinfo();
teacher.setUserId("teacher-1"); teacher.setRole(3); teacher.setSchoolId("school-zj");
Userinfo student = new Userinfo();
student.setUserId("student-1"); student.setRole(4); student.setSchoolId("school-zj"); student.setUsername("20260001"); student.setName("张三");
SchoolClass teachingClass = new SchoolClass();
teachingClass.setSchoolClassId("teach-2"); teachingClass.setSchoolId("school-zj"); teachingClass.setClassType("TEACHING"); teachingClass.setCreatedBy("teacher-1");
when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher);
when(controller.schoolClassMapper.selectByPrimaryKey("teach-2")).thenReturn(teachingClass);
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-zj")).thenReturn(true);
when(controller.userinfoMapper.selectBySchoolIdAndUsername("school-zj", "20260001")).thenReturn(student);
TeacherRosterStudentImportDTO row = new TeacherRosterStudentImportDTO(); row.setName("张三"); row.setUsername("20260001");
ResultEntity result = controller.importTeacherRosterRows(Collections.singletonList(row), "teach-2", "teacher-1");
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.userinfoMapper, never()).insertSelective(any(Userinfo.class));
verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class));
} }
} }

@ -697,7 +697,7 @@ class UserControllerTeacherAdminTest {
} }
@Test @Test
void importTeachingClassStudentRowsTransfersStudentFromOtherTeachingClass() { void importTeachingClassStudentRowsKeepsStudentInOtherTeachingClasses() {
UserController controller = controllerWithCommonMocks(); UserController controller = controllerWithCommonMocks();
SchoolClass teachingClass = classCreatedBy("teacher-1"); SchoolClass teachingClass = classCreatedBy("teacher-1");
teachingClass.setSchoolClassId("teaching-1"); teachingClass.setSchoolClassId("teaching-1");
@ -712,7 +712,8 @@ class UserControllerTeacherAdminTest {
ResultEntity result = controller.importTeachingClassStudentRows(Collections.singletonList(row), "teaching-1", "teacher-1"); ResultEntity result = controller.importTeachingClassStudentRows(Collections.singletonList(row), "teaching-1", "teacher-1");
assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.teachingClassStudentMapper).exitActiveByStudentUserIdExceptClass("student-1", "teaching-1"); verify(controller.teachingClassStudentMapper, never())
.exitActiveByStudentUserIdExceptClass(any(), any());
verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class)); verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class));
} }
@ -789,7 +790,7 @@ class UserControllerTeacherAdminTest {
} }
@Test @Test
void createTeachingClassByImportRowsTransfersStudentFromOtherTeachingClass() { void createTeachingClassByImportRowsKeepsStudentInOtherTeachingClasses() {
UserController controller = controllerWithCommonMocks(); UserController controller = controllerWithCommonMocks();
Userinfo student = student("student-1", "student-a", "2024001", "admin-1"); Userinfo student = student("student-1", "student-a", "2024001", "admin-1");
when(controller.schoolClassMapper.selectByExample(any())).thenReturn(Collections.emptyList()); when(controller.schoolClassMapper.selectByExample(any())).thenReturn(Collections.emptyList());
@ -806,7 +807,8 @@ class UserControllerTeacherAdminTest {
assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.schoolClassMapper).insert(any(SchoolClass.class)); verify(controller.schoolClassMapper).insert(any(SchoolClass.class));
verify(controller.teachingClassStudentMapper).exitActiveByStudentUserIdExceptClass(argThat(id -> "student-1".equals(id)), any()); verify(controller.teachingClassStudentMapper, never())
.exitActiveByStudentUserIdExceptClass(any(), any());
verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class)); verify(controller.teachingClassStudentMapper).insertSelective(any(TeachingClassStudent.class));
} }

@ -2,7 +2,9 @@ package com.sztzjy.linkCommerce.service.impl;
import com.sztzjy.linkCommerce.config.exception.handler.ServiceException; import com.sztzjy.linkCommerce.config.exception.handler.ServiceException;
import com.sztzjy.linkCommerce.entity.SchoolProductConfig; import com.sztzjy.linkCommerce.entity.SchoolProductConfig;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.SchoolProductConfigMapper; import com.sztzjy.linkCommerce.mapper.SchoolProductConfigMapper;
import com.sztzjy.linkCommerce.mapper.UserinfoMapper;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
@ -67,6 +69,20 @@ class SchoolProductConfigServiceImplTest {
&& "SCHOOL_ADMIN".equals(config.getStudentRosterOwner()))); && "SCHOOL_ADMIN".equals(config.getStudentRosterOwner())));
} }
@Test
void updateRejectsOrganizationModeChangeWhenAdministrativeDataExists() {
SchoolProductConfigServiceImpl service = new SchoolProductConfigServiceImpl();
service.schoolProductConfigMapper = mock(SchoolProductConfigMapper.class);
service.schoolClassMapper = mock(SchoolClassMapper.class);
service.userinfoMapper = mock(UserinfoMapper.class);
SchoolProductConfig current = config("school-standard", "ADMIN_CLASS_ENABLED", "SCHOOL_ADMIN");
when(service.schoolProductConfigMapper.selectByPrimaryKey("school-standard")).thenReturn(current);
when(service.schoolClassMapper.countByExample(org.mockito.ArgumentMatchers.any())).thenReturn(1L);
assertThrows(ServiceException.class, () -> service.updateConfig(
config("school-standard", "TEACHING_CLASS_ONLY", "TEACHER")));
}
private SchoolProductConfig config(String schoolId, String organizationMode, String rosterOwner) { private SchoolProductConfig config(String schoolId, String organizationMode, String rosterOwner) {
SchoolProductConfig config = new SchoolProductConfig(); SchoolProductConfig config = new SchoolProductConfig();
config.setSchoolId(schoolId); config.setSchoolId(schoolId);

Loading…
Cancel
Save