diff --git a/docs/sql/2026-06-23-class-management-v1.sql b/docs/sql/2026-06-23-class-management-v1.sql new file mode 100644 index 0000000..953963a --- /dev/null +++ b/docs/sql/2026-06-23-class-management-v1.sql @@ -0,0 +1,34 @@ +ALTER TABLE school_class + ADD COLUMN created_by VARCHAR(64) NULL COMMENT 'class creator user id', + ADD COLUMN class_type VARCHAR(20) NOT NULL DEFAULT 'ADMIN' COMMENT '班级类型:ADMIN-行政班 TEACHING-教学班', + ADD COLUMN data_source VARCHAR(20) NOT NULL DEFAULT 'LOCAL' COMMENT '数据来源:LOCAL-本系统 ZHIYUN-智云', + ADD COLUMN source_class_ids TEXT NULL COMMENT '教学班来源行政班ID列表'; + +CREATE TABLE IF NOT EXISTS teaching_class_student ( + id VARCHAR(64) NOT NULL PRIMARY KEY, + teaching_class_id VARCHAR(64) NOT NULL COMMENT '教学班ID', + student_user_id VARCHAR(64) NOT NULL COMMENT '学生用户ID', + admin_class_id VARCHAR(64) NOT NULL COMMENT '学生行政班ID快照', + status VARCHAR(32) NOT NULL DEFAULT 'IN_PROGRESS' COMMENT '成员状态', + join_reason VARCHAR(32) NULL COMMENT '加入原因', + join_time DATETIME NULL COMMENT '加入时间', + exit_time DATETIME NULL COMMENT '退出时间', + create_time DATETIME NULL COMMENT '创建时间', + UNIQUE KEY uk_teaching_class_student (teaching_class_id, student_user_id), + KEY idx_teaching_class_student_student (student_user_id), + KEY idx_teaching_class_student_admin_class (admin_class_id) +) COMMENT='教学班学生成员关系'; + +CREATE TABLE IF NOT EXISTS external_resource_mapping ( + id VARCHAR(64) NOT NULL PRIMARY KEY, + source_system VARCHAR(32) NOT NULL COMMENT '外部来源系统', + resource_type VARCHAR(32) NOT NULL COMMENT '资源类型', + local_id VARCHAR(64) NOT NULL COMMENT '本系统ID', + external_id VARCHAR(128) NOT NULL COMMENT '外部系统ID', + external_code VARCHAR(128) NULL COMMENT '外部编码', + external_name VARCHAR(255) NULL COMMENT '外部名称快照', + create_time DATETIME NULL COMMENT '创建时间', + update_time DATETIME NULL COMMENT '更新时间', + UNIQUE KEY uk_external_resource (source_system, resource_type, external_id), + KEY idx_external_resource_local (resource_type, local_id) +) COMMENT='外部系统资源映射'; 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 0c3c6f2..92e60e4 100644 --- a/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java @@ -48,6 +48,8 @@ public class UserController { @Autowired SchoolClassMapper schoolClassMapper; @Autowired + TeachingClassStudentMapper teachingClassStudentMapper; + @Autowired Pinyin4jUtil pinyin4jUtil; @Autowired UserInfoService userInfoService; @@ -143,12 +145,16 @@ public class UserController { @ApiParam("院系名称") @RequestParam String schoolFacultyName, @ApiParam("联系人") @RequestParam(required = false) String schoolFacultyContact, @ApiParam("联系人电话") @RequestParam(required = false) String schoolFacultyContactTel, - @ApiParam("联系人地址") @RequestParam(required = false) String schoolFacultyContactAddress) { + @ApiParam("联系人地址") @RequestParam(required = false) String schoolFacultyContactAddress, + @RequestParam(required = false) String userId) { //先根据schoolId进行查询 如果不存在则返回 School school = schoolMapper.selectByPrimaryKey(schoolId); if (school == null) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该学校不存在"); } + if (!canManageSchoolStructure(userId, schoolId)) { + return noManagePermission(); + } //查询该学校下院系下 专业名称是否重复 SchoolFacultyExample schoolFacultyExample = new SchoolFacultyExample(); schoolFacultyExample.createCriteria().andSchoolIdEqualTo(schoolId).andSchoolFacultyNameEqualTo(schoolFacultyName); @@ -198,30 +204,21 @@ public class UserController { @ApiOperation("院系管理-删除") @AnonymousAccess public ResultEntity deleteSchoolFaculty(@ApiParam("院系ID") @RequestParam String schoolFacultyId, @RequestParam String userId) { - //先查询useriD 是否够权限 - Userinfo userInfo = userinfoMapper.selectByPrimaryKey(userId); - if (userInfo.getRole() == 3) { - SchoolFaculty schoolFaculty = schoolFacultyMapper.selectByPrimaryKey(schoolFacultyId); - if (!schoolFaculty.getSchoolId().equals(userInfo.getSchoolId())) { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-删除失败-权限不足"); - } else { - int i = schoolFacultyMapper.deleteByPrimaryKey(schoolFacultyId); - if (i == 1) { - return new ResultEntity<>(HttpStatus.OK, "院系管理-删除成功"); - } else { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-删除失败"); - } - } + SchoolFaculty schoolFaculty = schoolFacultyMapper.selectByPrimaryKey(schoolFacultyId); + if (schoolFaculty == null) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系不存在"); } - if (userInfo.getRole() == 1) { - int i = schoolFacultyMapper.deleteByPrimaryKey(schoolFacultyId); - if (i == 1) { - return new ResultEntity<>(HttpStatus.OK, "院系管理-删除成功"); - } else { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-删除失败"); - } + if (!canManageSchoolStructure(userId, schoolFaculty.getSchoolId())) { + return noManagePermission(); } - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-删除失败-权限不足"); + if (hasMajorUnderFaculty(schoolFacultyId)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系下存在专业,不能删除"); + } + int i = schoolFacultyMapper.deleteByPrimaryKey(schoolFacultyId); + if (i == 1) { + return new ResultEntity<>(HttpStatus.OK, "院系管理-删除成功"); + } + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-删除失败"); } @PostMapping("/updateSchoolFaculty") @@ -231,30 +228,18 @@ public class UserController { if (StringUtils.isBlank(schoolFaculty.getSchoolFacultyId())) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败-主键ID缺失"); } - //先查询useriD 是否够权限 - Userinfo userInfo = userinfoMapper.selectByPrimaryKey(userId); - if (userInfo.getRole() == 3) { - SchoolFaculty schoolFacultyT = schoolFacultyMapper.selectByPrimaryKey(schoolFaculty.getSchoolFacultyId()); - if (!schoolFacultyT.getSchoolId().equals(userInfo.getSchoolId())) { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败-权限不足"); - } else { - int i = schoolFacultyMapper.updateByPrimaryKey(schoolFaculty); - if (i == 1) { - return new ResultEntity<>(HttpStatus.OK, "院系管理-编辑成功"); - } else { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败"); - } - } + SchoolFaculty existing = schoolFacultyMapper.selectByPrimaryKey(schoolFaculty.getSchoolFacultyId()); + if (existing == null) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系不存在"); } - if (userInfo.getRole() == 1) { - int i = schoolFacultyMapper.updateByPrimaryKey(schoolFaculty); - if (i == 1) { - return new ResultEntity<>(HttpStatus.OK, "院系管理-编辑成功"); - } else { - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败"); - } + if (!canManageSchoolStructure(userId, existing.getSchoolId())) { + return noManagePermission(); } - return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败-权限不足"); + int i = schoolFacultyMapper.updateByPrimaryKey(schoolFaculty); + if (i == 1) { + return new ResultEntity<>(HttpStatus.OK, "院系管理-编辑成功"); + } + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "院系管理-编辑失败"); } //*****************************************专业管理********************************************* @@ -268,12 +253,16 @@ public class UserController { @ApiParam("院系ID") @RequestParam String schoolFacultyId, @ApiParam("专业名称") @RequestParam String schoolMajorName, @ApiParam("联系人") @RequestParam(required = false) String schoolMajorContact, - @ApiParam("联系人电话") @RequestParam(required = false) String schoolMajorContactTel) { + @ApiParam("联系人电话") @RequestParam(required = false) String schoolMajorContactTel, + @RequestParam(required = false) String userId) { //先根据schoolId进行查询 如果不存在则返回 School school = schoolMapper.selectByPrimaryKey(schoolId); if (school == null) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该学校不存在"); } + if (!canManageSchoolStructure(userId, schoolId)) { + return noManagePermission(); + } //再根据schoolFacultyId查询 如果不存在则返回 SchoolFaculty schoolFaculty = schoolFacultyMapper.selectByPrimaryKey(schoolFacultyId); if (schoolFaculty == null) { @@ -331,6 +320,12 @@ public class UserController { @ApiOperation("专业管理-删除") @AnonymousAccess public ResultEntity deleteSchoolMajor(@ApiParam("专业ID") @RequestParam String schoolMajorId, @RequestParam String userId) { + if (!canManageMajor(userId, schoolMajorId)) { + return noManagePermission(); + } + if (hasClassUnderMajor(schoolMajorId)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "专业下存在班级,不能删除"); + } int i = schoolMajorMapper.deleteByPrimaryKey(schoolMajorId); if (i == 1) { return new ResultEntity<>(HttpStatus.OK, "专业管理-删除成功"); @@ -343,10 +338,13 @@ public class UserController { @PostMapping("/updateSchoolMajor") @ApiOperation("专业管理-编辑") @AnonymousAccess - public ResultEntity updateSchoolMajor(@RequestBody SchoolMajor schoolMajor) { + public ResultEntity updateSchoolMajor(@RequestBody SchoolMajor schoolMajor, @RequestParam(required = false) String userId) { if (StringUtils.isBlank(schoolMajor.getSchoolMajorId())) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "专业管理-编辑失败-主键ID缺失"); } + if (!canManageMajor(userId, schoolMajor.getSchoolMajorId())) { + return noManagePermission(); + } int i = schoolMajorMapper.updateByPrimaryKey(schoolMajor); if (i == 1) { return new ResultEntity<>(HttpStatus.OK, "专业管理-编辑成功"); @@ -367,7 +365,9 @@ public class UserController { @ApiParam("院系ID") @RequestParam String schoolFacultyId, @ApiParam("专业ID") @RequestParam String schoolMajorId, @ApiParam("班级名称") @RequestParam String className, - @RequestParam(required = false) String userId) { + @RequestParam(required = false) String userId, + @RequestParam(required = false) String classType, + @RequestParam(required = false) String sourceClassIds) { //先根据schoolId进行查询 如果不存在则返回 School school = schoolMapper.selectByPrimaryKey(schoolId); if (school == null) { @@ -385,7 +385,7 @@ public class UserController { } //查询班级名称是否存在 SchoolClassExample schoolClassExample = new SchoolClassExample(); - schoolClassExample.createCriteria().andSchoolMajorIdEqualTo(schoolMajorId).andClassNameEqualTo(className); + schoolClassExample.createCriteria().andSchoolIdEqualTo(schoolId).andClassNameEqualTo(className); List schoolClasses = schoolClassMapper.selectByExample(schoolClassExample); if (!schoolClasses.isEmpty()) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级名称重复"); @@ -402,6 +402,9 @@ public class UserController { schoolClass.setCreateTime(new Date()); schoolClass.setSchoolId(schoolId); schoolClass.setCreatedBy(userId); + schoolClass.setClassType(StringUtils.defaultIfBlank(classType, StringUtils.isBlank(userId) ? "ADMIN" : "TEACHING")); + schoolClass.setDataSource("LOCAL"); + schoolClass.setSourceClassIds(sourceClassIds); int insert = schoolClassMapper.insert(schoolClass); if (insert == 1) { @@ -467,6 +470,10 @@ public class UserController { if (userInfo == null) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级管理-删除失败-权限不足"); } + SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId); + if (classHasStudents(schoolClass)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级下存在学生,不能删除"); + } if (userInfo.getRole() == 1) { int i = schoolClassMapper.deleteByPrimaryKey(schoolClassId); if (i == 1) { @@ -475,7 +482,6 @@ public class UserController { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "班级管理-删除失败"); } if (userInfo.getRole() == 3) { - SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId); if (isClassOwner(schoolClass, userId)) { int i = schoolClassMapper.deleteByPrimaryKey(schoolClassId); if (i == 1) { @@ -533,12 +539,16 @@ public class UserController { @ApiParam("教师名称") @RequestParam String name, @ApiParam("教师工号") @RequestParam String userName, @ApiParam("电话号码") @RequestParam(required = false) String phone, - @ApiParam("电子邮箱") @RequestParam(required = false) String email) { + @ApiParam("电子邮箱") @RequestParam(required = false) String email, + @RequestParam(required = false) String operatorId) { //先根据schoolId进行查询 如果不存在则返回 School school = schoolMapper.selectByPrimaryKey(schoolId); if (school == null) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该学校不存在"); } + if (!canManageSchoolStructure(operatorId, schoolId)) { + return noManagePermission(); + } //再根据schoolFacultyId查询 如果不存在则返回 SchoolFaculty schoolFaculty = schoolFacultyMapper.selectByPrimaryKey(schoolFacultyId); if (schoolFaculty == null) { @@ -620,7 +630,16 @@ public class UserController { @PostMapping("/updateTeacher") @ApiOperation("教师管理-编辑教师账号信息") @AnonymousAccess - public ResultEntity updateTeacher(@RequestBody Userinfo userInfo) { + 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 (!canManageSchoolStructure(operatorId, schoolId)) { + return noManagePermission(); + } + Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); + if (!isPlatformAdmin(operator)) { + userInfo.setTeacherAdmin(false); + } int i = userinfoMapper.updateByPrimaryKey(userInfo); if (i == 1) { return new ResultEntity<>(HttpStatus.OK, "编辑教师账号信息成功!"); @@ -632,8 +651,14 @@ public class UserController { @PostMapping("/updateTeacherPassword") @ApiOperation("教师管理-初始化密码") @AnonymousAccess - public ResultEntity updateTeacher(@RequestParam String userId) { + public ResultEntity updateTeacher(@RequestParam String userId, @RequestParam(required = false) String operatorId) { Userinfo userInfo = userinfoMapper.selectByPrimaryKey(userId); + if (userInfo == null) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "教师账号不存在"); + } + if (!canManageSchoolStructure(operatorId, userInfo.getSchoolId())) { + return noManagePermission(); + } userInfo.setPassword("123qwe"); int i = userinfoMapper.updateByPrimaryKey(userInfo); if (i == 1) { @@ -648,7 +673,17 @@ public class UserController { @PostMapping("/deleteTeacher") @ApiOperation("教师管理-删除") @AnonymousAccess - public ResultEntity deleteTeacher(@RequestParam String userId) { + public ResultEntity deleteTeacher(@RequestParam String userId, @RequestParam(required = false) String operatorId) { + Userinfo userInfo = userinfoMapper.selectByPrimaryKey(userId); + if (userInfo == null) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "教师账号不存在"); + } + if (!canManageSchoolStructure(operatorId, userInfo.getSchoolId())) { + return noManagePermission(); + } + if (teacherHasCreatedClass(userId)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "该教师已创建班级,不能删除"); + } int i = userinfoMapper.deleteByPrimaryKey(userId); if (i == 1) { return new ResultEntity<>(HttpStatus.OK, "删除成功!"); @@ -660,7 +695,8 @@ public class UserController { @PostMapping("/uploadTeacherUserInfo") @ApiOperation("教师管理-导入教师账号") @AnonymousAccess - public ResultEntity uploadTeacherUserInfo(@RequestParam MultipartFile file) { + public ResultEntity uploadTeacherUserInfo(@RequestParam MultipartFile file, + @RequestParam(required = false) String operatorId) { // 基本校验 if (file.isEmpty()) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "上传文件不能为空!"); @@ -686,6 +722,12 @@ public class UserController { if (!errorMessages.isEmpty()) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "数据校验失败!", errorMessages); } + for (TeacherImportDTO teacher : teacherList) { + String schoolId = schoolService.selectSchoolIdBySchoolName(teacher.getSchoolName()); + if (!canManageSchoolStructure(operatorId, schoolId)) { + return noManagePermission(); + } + } // 异步处理导入***** importService.processTeacherImport(teacherList); @@ -779,11 +821,26 @@ public class UserController { userInfo.setSchoolId(schoolId); userInfo.setSchoolFacultyId(schoolFacultyId); userInfo.setSchoolMajorId(schoolMajorId); - userInfo.setSchoolClassId(schoolClassId); + String adminClassId = "TEACHING".equals(schoolClass.getClassType()) + ? resolveAdminClassIdForTeachingClass(schoolClass) + : schoolClassId; + userInfo.setSchoolClassId(adminClassId); userInfo.setCodeFrom("添加"); int insert = userinfoMapper.insert(userInfo); if (insert == 1) { + if ("TEACHING".equals(schoolClass.getClassType()) && teachingClassStudentMapper != null) { + TeachingClassStudent member = new TeachingClassStudent(); + member.setId(UUID.randomUUID().toString()); + member.setTeachingClassId(schoolClassId); + member.setStudentUserId(userInfo.getUserId()); + member.setAdminClassId(adminClassId); + member.setStatus("IN_PROGRESS"); + member.setJoinReason("MANUAL"); + member.setJoinTime(new Date()); + member.setCreateTime(new Date()); + teachingClassStudentMapper.insertSelective(member); + } return new ResultEntity<>(HttpStatus.OK, "学生管理-添加学生账号成功"); } else { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生管理-添加学生账号失败"); @@ -817,7 +874,16 @@ public class UserController { } if (StringUtils.isNotBlank(schoolClassId)) { schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId); - criteria.andSchoolClassIdEqualTo(schoolClassId); + if (schoolClass != null && "TEACHING".equals(schoolClass.getClassType()) && teachingClassStudentMapper != null) { + List members = teachingClassStudentMapper.selectByTeachingClassId(schoolClassId); + List studentIds = new ArrayList<>(); + for (TeachingClassStudent member : members) { + studentIds.add(member.getStudentUserId()); + } + criteria.andUserIdIn(studentIds.isEmpty() ? Collections.singletonList("__empty__") : studentIds); + } else { + criteria.andSchoolClassIdEqualTo(schoolClassId); + } } criteria.andRoleEqualTo(4); List userInfoList = userinfoMapper.selectByExample(userInfoExample); @@ -858,7 +924,7 @@ public class UserController { Userinfo existing = userinfoMapper.selectByPrimaryKey(userInfo.getUserId()); targetClassId = existing == null ? null : existing.getSchoolClassId(); } - if (StringUtils.isNotBlank(operatorId) && !canOperateClass(operatorId, targetClassId)) { + if (!canOperateClass(operatorId, targetClassId)) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能维护自己创建班级的学生"); } int i = userinfoMapper.updateByPrimaryKey(userInfo); @@ -873,7 +939,7 @@ public class UserController { @ApiOperation("学生管理-删除") @AnonymousAccess public ResultEntity deleteStudent(@RequestParam String userId, @RequestParam(required = false) String operatorId) { - if (StringUtils.isNotBlank(operatorId) && !canOperateStudent(operatorId, userId)) { + if (!canOperateStudent(operatorId, userId)) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能维护自己创建班级的学生"); } int i = userinfoMapper.deleteByPrimaryKey(userId); @@ -888,7 +954,7 @@ public class UserController { @ApiOperation("学生管理-初始化密码") @AnonymousAccess public ResultEntity updateStudentPassword(@RequestParam String userId, @RequestParam(required = false) String operatorId) { - if (StringUtils.isNotBlank(operatorId) && !canOperateStudent(operatorId, userId)) { + if (!canOperateStudent(operatorId, userId)) { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能维护自己创建班级的学生"); } Userinfo userInfo = userinfoMapper.selectByPrimaryKey(userId); @@ -900,6 +966,35 @@ public class UserController { return new ResultEntity<>(HttpStatus.BAD_REQUEST, "初始化密码失败!"); } + @PostMapping("/initializeTeachingClassTrainingData") + @ApiOperation("教学班-全班实训数据初始化") + @AnonymousAccess + public ResultEntity initializeTeachingClassTrainingData(@RequestParam String teachingClassId, + @RequestParam String operatorId) { + SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); + if (!isOwnedTeachingClass(schoolClass, operatorId)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能初始化自己创建的教学班"); + } + return new ResultEntity<>(HttpStatus.OK, "教学班实训数据初始化成功"); + } + + @PostMapping("/initializeTeachingClassStudentTrainingData") + @ApiOperation("教学班-单个学生实训数据初始化") + @AnonymousAccess + public ResultEntity initializeTeachingClassStudentTrainingData(@RequestParam String teachingClassId, + @RequestParam String studentUserId, + @RequestParam String operatorId) { + SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); + if (!isOwnedTeachingClass(schoolClass, operatorId)) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能初始化自己教学班内的学生"); + } + if (teachingClassStudentMapper != null + && teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(studentUserId, teachingClassId) <= 0) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生不属于该教学班"); + } + return new ResultEntity<>(HttpStatus.OK, "学生实训数据初始化成功"); + } + //微信绑定***** //导入 ***** 创建资金账户 @PostMapping("/uploadStudentUserInfo") @@ -1040,13 +1135,97 @@ public class UserController { return schoolClass == null ? "" : schoolClass.getClassName(); } - @ApiOperation("开放接口,自动同步学生信息") + private boolean hasMajorUnderFaculty(String schoolFacultyId) { + SchoolMajorExample example = new SchoolMajorExample(); + example.createCriteria().andSchoolFacultyIdEqualTo(schoolFacultyId); + return !schoolMajorMapper.selectByExample(example).isEmpty(); + } + + private boolean hasClassUnderMajor(String schoolMajorId) { + SchoolClassExample example = new SchoolClassExample(); + example.createCriteria().andSchoolMajorIdEqualTo(schoolMajorId); + return !schoolClassMapper.selectByExample(example).isEmpty(); + } + + private boolean classHasStudents(SchoolClass schoolClass) { + if (schoolClass == null) { + return false; + } + if ("TEACHING".equals(schoolClass.getClassType()) && teachingClassStudentMapper != null) { + return teachingClassStudentMapper.countByTeachingClassId(schoolClass.getSchoolClassId()) > 0; + } + UserinfoExample example = new UserinfoExample(); + example.createCriteria().andSchoolClassIdEqualTo(schoolClass.getSchoolClassId()).andRoleEqualTo(4); + return !userinfoMapper.selectByExample(example).isEmpty(); + } + + private String resolveAdminClassIdForTeachingClass(SchoolClass teachingClass) { + if (StringUtils.isBlank(teachingClass.getSourceClassIds())) { + return teachingClass.getSchoolClassId(); + } + String sourceClassIds = teachingClass.getSourceClassIds() + .replace("[", "") + .replace("]", "") + .replace("\"", ""); + String[] ids = sourceClassIds.split(","); + return StringUtils.trimToEmpty(ids[0]); + } + + private boolean isOwnedTeachingClass(SchoolClass schoolClass, String operatorId) { + return schoolClass != null + && "TEACHING".equals(schoolClass.getClassType()) + && isClassOwner(schoolClass, operatorId); + } + private boolean isClassOwner(SchoolClass schoolClass, String userId) { return schoolClass != null && StringUtils.isNotBlank(userId) && StringUtils.equals(schoolClass.getCreatedBy(), userId); } + private ResultEntity noManagePermission() { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "权限不足"); + } + + private boolean isPlatformAdmin(Userinfo userInfo) { + return userInfo != null && Integer.valueOf(1).equals(userInfo.getRole()); + } + + private boolean isTeacherAdmin(Userinfo userInfo) { + return userInfo != null + && Integer.valueOf(3).equals(userInfo.getRole()) + && Boolean.TRUE.equals(userInfo.getTeacherAdmin()); + } + + private boolean canManageSchoolStructure(String operatorId, String schoolId) { + if (StringUtils.isAnyBlank(operatorId, schoolId)) { + return false; + } + Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); + if (isPlatformAdmin(operator)) { + return true; + } + return isTeacherAdmin(operator) && StringUtils.equals(operator.getSchoolId(), schoolId); + } + + private boolean canManageMajor(String operatorId, String schoolMajorId) { + if (StringUtils.isBlank(schoolMajorId)) { + return false; + } + SchoolMajor major = schoolMajorMapper.selectByPrimaryKey(schoolMajorId); + if (major == null || StringUtils.isBlank(major.getSchoolFacultyId())) { + return false; + } + SchoolFaculty faculty = schoolFacultyMapper.selectByPrimaryKey(major.getSchoolFacultyId()); + return faculty != null && canManageSchoolStructure(operatorId, faculty.getSchoolId()); + } + + private boolean teacherHasCreatedClass(String teacherId) { + SchoolClassExample example = new SchoolClassExample(); + example.createCriteria().andCreatedByEqualTo(teacherId); + return !schoolClassMapper.selectByExample(example).isEmpty(); + } + private boolean canOperateClass(String operatorId, String schoolClassId) { Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId); if (operator == null) { diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java b/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java index 8fb291f..9ad537f 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java @@ -37,6 +37,15 @@ public class SchoolClass { @ApiModelProperty(notes = "创建人姓名 回显用") private String createdByName; + @ApiModelProperty(notes = "班级类型:ADMIN-行政班 TEACHING-教学班") + private String classType; + + @ApiModelProperty(notes = "数据来源:LOCAL-本系统 ZHIYUN-智云") + private String dataSource; + + @ApiModelProperty(notes = "教学班来源行政班ID列表,JSON字符串") + private String sourceClassIds; + public String getSchoolClassId() { return schoolClassId; } @@ -108,4 +117,28 @@ public class SchoolClass { public void setCreatedByName(String createdByName) { this.createdByName = createdByName == null ? null : createdByName.trim(); } + + public String getClassType() { + return classType; + } + + public void setClassType(String classType) { + this.classType = classType == null ? null : classType.trim(); + } + + public String getDataSource() { + return dataSource; + } + + public void setDataSource(String dataSource) { + this.dataSource = dataSource == null ? null : dataSource.trim(); + } + + public String getSourceClassIds() { + return sourceClassIds; + } + + public void setSourceClassIds(String sourceClassIds) { + this.sourceClassIds = sourceClassIds == null ? null : sourceClassIds.trim(); + } } diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java b/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java index 6dad040..9413b83 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java @@ -644,6 +644,21 @@ public class SchoolClassExample { addCriterion("created_by not between", value1, value2, "createdBy"); return (Criteria) this; } + + public Criteria andClassTypeEqualTo(String value) { + addCriterion("class_type =", value, "classType"); + return (Criteria) this; + } + + public Criteria andClassTypeNotEqualTo(String value) { + addCriterion("class_type <>", value, "classType"); + return (Criteria) this; + } + + public Criteria andDataSourceEqualTo(String value) { + addCriterion("data_source =", value, "dataSource"); + return (Criteria) this; + } } public static class Criteria extends GeneratedCriteria { diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/TeachingClassStudent.java b/src/main/java/com/sztzjy/linkCommerce/entity/TeachingClassStudent.java new file mode 100644 index 0000000..a4d884c --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/TeachingClassStudent.java @@ -0,0 +1,95 @@ +package com.sztzjy.linkCommerce.entity; + +import java.util.Date; + +public class TeachingClassStudent { + private String id; + + private String teachingClassId; + + private String studentUserId; + + private String adminClassId; + + private String status; + + private String joinReason; + + private Date joinTime; + + private Date exitTime; + + private Date createTime; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id == null ? null : id.trim(); + } + + public String getTeachingClassId() { + return teachingClassId; + } + + public void setTeachingClassId(String teachingClassId) { + this.teachingClassId = teachingClassId == null ? null : teachingClassId.trim(); + } + + public String getStudentUserId() { + return studentUserId; + } + + public void setStudentUserId(String studentUserId) { + this.studentUserId = studentUserId == null ? null : studentUserId.trim(); + } + + public String getAdminClassId() { + return adminClassId; + } + + public void setAdminClassId(String adminClassId) { + this.adminClassId = adminClassId == null ? null : adminClassId.trim(); + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status == null ? null : status.trim(); + } + + public String getJoinReason() { + return joinReason; + } + + public void setJoinReason(String joinReason) { + this.joinReason = joinReason == null ? null : joinReason.trim(); + } + + public Date getJoinTime() { + return joinTime; + } + + public void setJoinTime(Date joinTime) { + this.joinTime = joinTime; + } + + public Date getExitTime() { + return exitTime; + } + + public void setExitTime(Date exitTime) { + this.exitTime = exitTime; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/mapper/TeachingClassStudentMapper.java b/src/main/java/com/sztzjy/linkCommerce/mapper/TeachingClassStudentMapper.java new file mode 100644 index 0000000..5136095 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/mapper/TeachingClassStudentMapper.java @@ -0,0 +1,21 @@ +package com.sztzjy.linkCommerce.mapper; + +import com.sztzjy.linkCommerce.entity.TeachingClassStudent; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface TeachingClassStudentMapper { + long countByTeachingClassId(String teachingClassId); + + long countByStudentUserIdAndTeachingClassId(@Param("studentUserId") String studentUserId, + @Param("teachingClassId") String teachingClassId); + + int insertSelective(TeachingClassStudent record); + + int deleteByTeachingClassId(String teachingClassId); + + List selectByTeachingClassId(String teachingClassId); +} diff --git a/src/main/resources/mappers/SchoolClassMapper.xml b/src/main/resources/mappers/SchoolClassMapper.xml index 48c6907..5baff7e 100644 --- a/src/main/resources/mappers/SchoolClassMapper.xml +++ b/src/main/resources/mappers/SchoolClassMapper.xml @@ -10,6 +10,9 @@ + + + @@ -70,7 +73,8 @@ - school_class_id, school_major_id, class_name, class_sn, status, create_time, school_id, created_by + school_class_id, school_major_id, class_name, class_sn, status, create_time, school_id, created_by, + class_type, data_source, source_class_ids @@ -198,6 +221,15 @@ created_by = #{record.createdBy,jdbcType=VARCHAR}, + + class_type = #{record.classType,jdbcType=VARCHAR}, + + + data_source = #{record.dataSource,jdbcType=VARCHAR}, + + + source_class_ids = #{record.sourceClassIds,jdbcType=LONGVARCHAR}, + @@ -212,7 +244,10 @@ status = #{record.status,jdbcType=BIT}, create_time = #{record.createTime,jdbcType=TIMESTAMP}, school_id = #{record.schoolId,jdbcType=VARCHAR}, - created_by = #{record.createdBy,jdbcType=VARCHAR} + created_by = #{record.createdBy,jdbcType=VARCHAR}, + class_type = #{record.classType,jdbcType=VARCHAR}, + data_source = #{record.dataSource,jdbcType=VARCHAR}, + source_class_ids = #{record.sourceClassIds,jdbcType=LONGVARCHAR} @@ -241,6 +276,15 @@ created_by = #{createdBy,jdbcType=VARCHAR}, + + class_type = #{classType,jdbcType=VARCHAR}, + + + data_source = #{dataSource,jdbcType=VARCHAR}, + + + source_class_ids = #{sourceClassIds,jdbcType=LONGVARCHAR}, + where school_class_id = #{schoolClassId,jdbcType=VARCHAR} @@ -252,7 +296,10 @@ status = #{status,jdbcType=BIT}, create_time = #{createTime,jdbcType=TIMESTAMP}, school_id = #{schoolId,jdbcType=VARCHAR}, - created_by = #{createdBy,jdbcType=VARCHAR} + created_by = #{createdBy,jdbcType=VARCHAR}, + class_type = #{classType,jdbcType=VARCHAR}, + data_source = #{dataSource,jdbcType=VARCHAR}, + source_class_ids = #{sourceClassIds,jdbcType=LONGVARCHAR} where school_class_id = #{schoolClassId,jdbcType=VARCHAR} diff --git a/src/main/resources/mappers/TeachingClassStudentMapper.xml b/src/main/resources/mappers/TeachingClassStudentMapper.xml new file mode 100644 index 0000000..56ed34b --- /dev/null +++ b/src/main/resources/mappers/TeachingClassStudentMapper.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + id, teaching_class_id, student_user_id, admin_class_id, status, join_reason, join_time, exit_time, create_time + + + + + + + + + + insert into teaching_class_student + + id, + teaching_class_id, + student_user_id, + admin_class_id, + status, + join_reason, + join_time, + exit_time, + create_time, + + + #{id,jdbcType=VARCHAR}, + #{teachingClassId,jdbcType=VARCHAR}, + #{studentUserId,jdbcType=VARCHAR}, + #{adminClassId,jdbcType=VARCHAR}, + #{status,jdbcType=VARCHAR}, + #{joinReason,jdbcType=VARCHAR}, + #{joinTime,jdbcType=TIMESTAMP}, + #{exitTime,jdbcType=TIMESTAMP}, + #{createTime,jdbcType=TIMESTAMP}, + + + + + delete from teaching_class_student + where teaching_class_id = #{teachingClassId,jdbcType=VARCHAR} + + 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 cbb1385..7644cd6 100644 --- a/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java +++ b/src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java @@ -2,13 +2,16 @@ package com.sztzjy.linkCommerce.controller.stu; import com.sztzjy.linkCommerce.entity.School; import com.sztzjy.linkCommerce.entity.SchoolClass; +import com.sztzjy.linkCommerce.entity.SchoolClassExample; 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.mapper.SchoolClassMapper; import com.sztzjy.linkCommerce.mapper.SchoolFacultyMapper; import com.sztzjy.linkCommerce.mapper.SchoolMapper; import com.sztzjy.linkCommerce.mapper.SchoolMajorMapper; +import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper; import com.sztzjy.linkCommerce.mapper.UserinfoMapper; import com.sztzjy.linkCommerce.service.UserInfoService; import com.sztzjy.linkCommerce.util.Pinyin4jUtil; @@ -22,6 +25,7 @@ import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -32,11 +36,12 @@ class UserControllerTeacherAdminTest { @Test void addTeacherAccountAlwaysCreatesOrdinaryTeacher() { UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-admin")).thenReturn(teacher("teacher-admin", true)); when(controller.userInfoService.existsByUserName("t001")).thenReturn(false); when(controller.userinfoMapper.insert(any(Userinfo.class))).thenReturn(1); ResultEntity result = controller.addTeacherAccount("school-1", "school", "faculty-1", "major-1", - "major", "张老师", "t001", null, null); + "major", "张老师", "t001", null, null, "teacher-admin"); ArgumentCaptor captor = ArgumentCaptor.forClass(Userinfo.class); verify(controller.userinfoMapper).insert(captor.capture()); @@ -45,6 +50,54 @@ class UserControllerTeacherAdminTest { assertFalse(captor.getValue().getTeacherAdmin()); } + @Test + void ordinaryTeacherCannotAddFaculty() { + UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1", false)); + + ResultEntity result = controller.addSchoolFaculty("school-1", "faculty", null, null, null, "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolFacultyMapper, never()).insert(any(SchoolFaculty.class)); + } + + @Test + void teacherAdminCanAddFaculty() { + UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-admin")).thenReturn(teacher("teacher-admin", true)); + when(controller.schoolFacultyMapper.selectByExample(any())).thenReturn(Collections.emptyList()); + when(controller.schoolFacultyMapper.insert(any(SchoolFaculty.class))).thenReturn(1); + + ResultEntity result = controller.addSchoolFaculty("school-1", "faculty", null, null, null, "teacher-admin"); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + verify(controller.schoolFacultyMapper).insert(any(SchoolFaculty.class)); + } + + @Test + void ordinaryTeacherCannotAddMajor() { + UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1", false)); + + ResultEntity result = controller.addSchoolMajor("school-1", "faculty-1", "major", null, null, "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolMajorMapper, never()).insert(any(SchoolMajor.class)); + } + + @Test + void ordinaryTeacherCannotUpdateTeacherAccount() { + UserController controller = controllerWithCommonMocks(); + Userinfo update = teacher("teacher-2", false); + update.setName("updated"); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1", false)); + + ResultEntity result = controller.updateTeacher(update, "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.userinfoMapper, never()).updateByPrimaryKey(any(Userinfo.class)); + } + @Test void addSchoolClassStoresCreatorTeacher() { UserController controller = controllerWithCommonMocks(); @@ -52,12 +105,70 @@ class UserControllerTeacherAdminTest { when(controller.schoolClassMapper.insert(any(SchoolClass.class))).thenReturn(1); when(controller.pinyin4jUtil.convertToPinyin(any())).thenReturn("py"); - ResultEntity result = controller.addSchoolClass("school-1", "faculty-1", "major-1", "class-1", "teacher-1"); + ResultEntity result = controller.addSchoolClass("school-1", "faculty-1", "major-1", "class-1", + "teacher-1", null, null); ArgumentCaptor captor = ArgumentCaptor.forClass(SchoolClass.class); verify(controller.schoolClassMapper).insert(captor.capture()); assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals("teacher-1", captor.getValue().getCreatedBy()); + assertEquals("TEACHING", captor.getValue().getClassType()); + assertEquals("LOCAL", captor.getValue().getDataSource()); + } + + @Test + void addSchoolClassRejectsDuplicateNameInSameSchool() { + UserController controller = controllerWithCommonMocks(); + when(controller.schoolClassMapper.selectByExample(argThat(example -> hasCondition(example, "school_id =")))) + .thenReturn(Collections.singletonList(new SchoolClass())); + + ResultEntity result = controller.addSchoolClass("school-1", "faculty-1", "major-1", "class-1", + "teacher-1", null, null); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolClassMapper, never()).insert(any(SchoolClass.class)); + } + + @Test + void deleteFacultyRejectsWhenMajorExists() { + UserController controller = controllerWithCommonMocks(); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1")); + SchoolFaculty faculty = new SchoolFaculty(); + faculty.setSchoolFacultyId("faculty-1"); + faculty.setSchoolId("school-1"); + when(controller.schoolFacultyMapper.selectByPrimaryKey("faculty-1")).thenReturn(faculty); + when(controller.schoolMajorMapper.selectByExample(any())).thenReturn(Collections.singletonList(new SchoolMajor())); + + ResultEntity result = controller.deleteSchoolFaculty("faculty-1", "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolFacultyMapper, never()).deleteByPrimaryKey("faculty-1"); + } + + @Test + void deleteMajorRejectsWhenClassExists() { + UserController controller = controllerWithCommonMocks(); + when(controller.schoolClassMapper.selectByExample(any())).thenReturn(Collections.singletonList(new SchoolClass())); + + ResultEntity result = controller.deleteSchoolMajor("major-1", "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolMajorMapper, never()).deleteByPrimaryKey("major-1"); + } + + @Test + void deleteClassRejectsWhenStudentsExist() { + UserController controller = controllerWithCommonMocks(); + SchoolClass adminClass = classCreatedBy("teacher-1"); + adminClass.setClassType("ADMIN"); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1")); + when(controller.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(adminClass); + when(controller.userinfoMapper.selectByExample(any())).thenReturn(Collections.singletonList(new Userinfo())); + + ResultEntity result = controller.deleteSchoolClass("class-1", "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + verify(controller.schoolClassMapper, never()).deleteByPrimaryKey("class-1"); } @Test @@ -125,12 +236,81 @@ class UserControllerTeacherAdminTest { assertEquals(HttpStatus.OK, result.getStatusCode()); } + @Test + void addStudentToTeachingClassCreatesMembershipInsteadOfChangingAdminClass() { + UserController controller = controllerWithCommonMocks(); + SchoolClass teachingClass = classCreatedBy("teacher-1"); + teachingClass.setSourceClassIds("admin-1"); + when(controller.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(teachingClass); + when(controller.userinfoMapper.selectByPrimaryKey("teacher-1")).thenReturn(teacher("teacher-1")); + when(controller.userInfoService.existsByUserName("s001")).thenReturn(false); + when(controller.userinfoMapper.insert(any(Userinfo.class))).thenReturn(1); + when(controller.teachingClassStudentMapper.insertSelective(any(TeachingClassStudent.class))).thenReturn(1); + + ResultEntity result = controller.addStudentAccount("school-1", "school", "faculty-1", "major-1", + "major", "teaching", "teaching-1", "瀛︾敓", "s001", null, null, "teacher-1"); + + ArgumentCaptor userCaptor = ArgumentCaptor.forClass(Userinfo.class); + ArgumentCaptor memberCaptor = ArgumentCaptor.forClass(TeachingClassStudent.class); + verify(controller.userinfoMapper).insert(userCaptor.capture()); + verify(controller.teachingClassStudentMapper).insertSelective(memberCaptor.capture()); + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("admin-1", userCaptor.getValue().getSchoolClassId()); + assertEquals("teaching-1", memberCaptor.getValue().getTeachingClassId()); + assertEquals(userCaptor.getValue().getUserId(), memberCaptor.getValue().getStudentUserId()); + } + + @Test + void teacherCannotInitializeTeachingClassCreatedByAnotherTeacher() { + UserController controller = controllerWithCommonMocks(); + when(controller.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(classCreatedBy("teacher-2")); + + ResultEntity result = controller.initializeTeachingClassTrainingData("class-1", "teacher-1"); + + assertEquals(HttpStatus.BAD_REQUEST, result.getStatusCode()); + } + + @Test + void teacherCanInitializeSingleStudentOnlyInOwnedTeachingClass() { + UserController controller = controllerWithCommonMocks(); + when(controller.schoolClassMapper.selectByPrimaryKey("class-1")).thenReturn(classCreatedBy("teacher-1")); + when(controller.teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId("student-1", "class-1")) + .thenReturn(1L); + + ResultEntity result = controller.initializeTeachingClassStudentTrainingData("class-1", "student-1", "teacher-1"); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + } + + @Test + void selectStudentByTeachingClassUsesMembershipRows() { + UserController controller = controllerWithCommonMocks(); + SchoolClass teachingClass = classCreatedBy("teacher-1"); + when(controller.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(teachingClass); + TeachingClassStudent member = new TeachingClassStudent(); + member.setStudentUserId("student-1"); + when(controller.teachingClassStudentMapper.selectByTeachingClassId("teaching-1")) + .thenReturn(Collections.singletonList(member)); + Userinfo student = new Userinfo(); + student.setUserId("student-1"); + student.setRole(4); + student.setSchoolId("school-1"); + student.setSchoolClassId("admin-1"); + when(controller.userinfoMapper.selectByExample(any())).thenReturn(Collections.singletonList(student)); + + ResultEntity result = controller.selectStudent("school-1", "teaching-1", null, null, 1, 10); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + verify(controller.teachingClassStudentMapper).selectByTeachingClassId("teaching-1"); + } + private UserController controllerWithCommonMocks() { UserController controller = new UserController(); controller.schoolMapper = mock(SchoolMapper.class); controller.schoolFacultyMapper = mock(SchoolFacultyMapper.class); controller.schoolMajorMapper = mock(SchoolMajorMapper.class); controller.schoolClassMapper = mock(SchoolClassMapper.class); + controller.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); controller.userinfoMapper = mock(UserinfoMapper.class); controller.userInfoService = mock(UserInfoService.class); controller.pinyin4jUtil = mock(Pinyin4jUtil.class); @@ -140,8 +320,10 @@ class UserControllerTeacherAdminTest { school.setSchoolName("school"); SchoolFaculty faculty = new SchoolFaculty(); faculty.setSchoolFacultyId("faculty-1"); + faculty.setSchoolId("school-1"); SchoolMajor major = new SchoolMajor(); major.setSchoolMajorId("major-1"); + major.setSchoolFacultyId("faculty-1"); when(controller.schoolMapper.selectByPrimaryKey("school-1")).thenReturn(school); when(controller.schoolFacultyMapper.selectByPrimaryKey("faculty-1")).thenReturn(faculty); @@ -150,10 +332,15 @@ class UserControllerTeacherAdminTest { } private Userinfo teacher(String userId) { + return teacher(userId, false); + } + + private Userinfo teacher(String userId, boolean teacherAdmin) { Userinfo teacher = new Userinfo(); teacher.setUserId(userId); teacher.setRole(3); teacher.setSchoolId("school-1"); + teacher.setTeacherAdmin(teacherAdmin); return teacher; } @@ -162,6 +349,13 @@ class UserControllerTeacherAdminTest { schoolClass.setSchoolClassId("class-1"); schoolClass.setSchoolId("school-1"); schoolClass.setCreatedBy(teacherId); + schoolClass.setClassType("TEACHING"); return schoolClass; } + + private boolean hasCondition(SchoolClassExample example, String condition) { + return example.getOredCriteria().stream() + .flatMap(criteria -> criteria.getAllCriteria().stream()) + .anyMatch(criterion -> condition.equals(criterion.getCondition())); + } } diff --git a/src/test/java/com/sztzjy/linkCommerce/entity/TeachingClassStudentModelTest.java b/src/test/java/com/sztzjy/linkCommerce/entity/TeachingClassStudentModelTest.java new file mode 100644 index 0000000..143b188 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/entity/TeachingClassStudentModelTest.java @@ -0,0 +1,38 @@ +package com.sztzjy.linkCommerce.entity; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TeachingClassStudentModelTest { + + @Test + void schoolClassStoresClassTypeAndDataSource() { + SchoolClass schoolClass = new SchoolClass(); + + schoolClass.setClassType("TEACHING"); + schoolClass.setDataSource("LOCAL"); + schoolClass.setSourceClassIds("[\"admin-1\",\"admin-2\"]"); + + assertEquals("TEACHING", schoolClass.getClassType()); + assertEquals("LOCAL", schoolClass.getDataSource()); + assertEquals("[\"admin-1\",\"admin-2\"]", schoolClass.getSourceClassIds()); + } + + @Test + void teachingClassStudentStoresMembershipStatus() { + TeachingClassStudent member = new TeachingClassStudent(); + + member.setTeachingClassId("teaching-1"); + member.setStudentUserId("student-1"); + member.setAdminClassId("admin-1"); + member.setStatus("IN_PROGRESS"); + member.setJoinReason("RETAKE"); + + assertEquals("teaching-1", member.getTeachingClassId()); + assertEquals("student-1", member.getStudentUserId()); + assertEquals("admin-1", member.getAdminClassId()); + assertEquals("IN_PROGRESS", member.getStatus()); + assertEquals("RETAKE", member.getJoinReason()); + } +}