feat: expand teacher admin student roster scope

main
chenyuan 4 weeks ago
parent 1ec067d77e
commit d3cff4553c

@ -893,8 +893,8 @@ public class UserController {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护学生名单"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护学生名单");
} }
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(teachingClass, operatorId)) { if (!canManageTeachingClass(operator, teachingClass)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择自己创建的教学班"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择可维护的教学班");
} }
if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) { if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空");
@ -938,8 +938,8 @@ public class UserController {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该学生名单"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权维护该学生名单");
} }
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(teachingClass, operatorId)) { if (!canManageTeachingClass(operator, teachingClass)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择自己创建的教学班"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能选择可维护的教学班");
} }
if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) { if (StringUtils.isAnyBlank(StringUtils.trimToNull(name), StringUtils.trimToNull(userName))) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "学生姓名和学号不能为空");
@ -1002,11 +1002,11 @@ public class UserController {
criteria.andUsernameEqualTo(userName); criteria.andUsernameEqualTo(userName);
} }
if (teacherRosterScope) { if (teacherRosterScope) {
List<String> ownedStudentIds = resolveOwnedRosterStudentIds(operator, schoolClassId); List<String> managedStudentIds = resolveManagedRosterStudentIds(operator, schoolClassId);
if (ownedStudentIds == null) { if (managedStudentIds == null) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能查看自己教学班内的学生"); return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权查看该教学班内的学生");
} }
criteria.andUserIdIn(ownedStudentIds.isEmpty() ? Collections.singletonList("__empty__") : ownedStudentIds); criteria.andUserIdIn(managedStudentIds.isEmpty() ? Collections.singletonList("__empty__") : managedStudentIds);
} }
if (StringUtils.isNotBlank(schoolClassId)) { if (StringUtils.isNotBlank(schoolClassId)) {
schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId); schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId);
@ -1053,21 +1053,25 @@ public class UserController {
} }
//编辑 //编辑
private List<String> resolveOwnedRosterStudentIds(Userinfo operator, String teachingClassId) { private List<String> resolveManagedRosterStudentIds(Userinfo operator, String teachingClassId) {
if (!isSchoolTeacher(operator) || teachingClassStudentMapper == null) { if (!isSchoolTeacher(operator) || teachingClassStudentMapper == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<SchoolClass> teachingClasses; List<SchoolClass> teachingClasses;
if (StringUtils.isNotBlank(teachingClassId)) { if (StringUtils.isNotBlank(teachingClassId)) {
SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); SchoolClass teachingClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(teachingClass, operator.getUserId())) { if (!canManageTeachingClass(operator, teachingClass)) {
return null; return null;
} }
teachingClasses = Collections.singletonList(teachingClass); teachingClasses = Collections.singletonList(teachingClass);
} else { } else {
SchoolClassExample example = new SchoolClassExample(); SchoolClassExample example = new SchoolClassExample();
example.createCriteria().andSchoolIdEqualTo(operator.getSchoolId()) SchoolClassExample.Criteria criteria = example.createCriteria()
.andCreatedByEqualTo(operator.getUserId()).andClassTypeEqualTo("TEACHING"); .andSchoolIdEqualTo(operator.getSchoolId())
.andClassTypeEqualTo("TEACHING");
if (!isTeacherAdmin(operator)) {
criteria.andCreatedByEqualTo(operator.getUserId());
}
teachingClasses = schoolClassMapper.selectByExample(example); teachingClasses = schoolClassMapper.selectByExample(example);
} }
Set<String> studentIds = new LinkedHashSet<>(); Set<String> studentIds = new LinkedHashSet<>();
@ -1157,8 +1161,9 @@ public class UserController {
public ResultEntity initializeTeachingClassTrainingData(@RequestParam String teachingClassId, public ResultEntity initializeTeachingClassTrainingData(@RequestParam String teachingClassId,
@RequestParam String operatorId) { @RequestParam String operatorId) {
SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(schoolClass, operatorId)) { Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId);
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能初始化自己创建的教学班"); if (!canManageTeachingClass(operator, schoolClass)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权初始化该教学班");
} }
List<TeachingClassStudent> members = teachingClassStudentMapper.selectByTeachingClassId(teachingClassId); List<TeachingClassStudent> members = teachingClassStudentMapper.selectByTeachingClassId(teachingClassId);
if (members == null) { if (members == null) {
@ -1179,8 +1184,9 @@ public class UserController {
@RequestParam String studentUserId, @RequestParam String studentUserId,
@RequestParam String operatorId) { @RequestParam String operatorId) {
SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId); SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(teachingClassId);
if (!isOwnedTeachingClass(schoolClass, operatorId)) { Userinfo operator = userinfoMapper.selectByPrimaryKey(operatorId);
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "只能初始化自己教学班内的学生"); if (!canManageTeachingClass(operator, schoolClass)) {
return new ResultEntity<>(HttpStatus.BAD_REQUEST, "无权初始化该教学班内的学生");
} }
if (teachingClassStudentMapper != null if (teachingClassStudentMapper != null
&& teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(studentUserId, teachingClassId) <= 0) { && teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId(studentUserId, teachingClassId) <= 0) {
@ -1569,13 +1575,13 @@ public class UserController {
UserinfoExample userInfoExample = new UserinfoExample(); UserinfoExample userInfoExample = new UserinfoExample();
userInfoExample.createCriteria().andSchoolIdEqualTo(schoolId).andRoleEqualTo(4); userInfoExample.createCriteria().andSchoolIdEqualTo(schoolId).andRoleEqualTo(4);
if (teacherRosterScope) { if (teacherRosterScope) {
List<String> ownedStudentIds = resolveOwnedRosterStudentIds(operator, schoolClassId); List<String> managedStudentIds = resolveManagedRosterStudentIds(operator, schoolClassId);
if (ownedStudentIds == null) { if (managedStudentIds == null) {
response.setStatus(HttpStatus.BAD_REQUEST.value()); response.setStatus(HttpStatus.BAD_REQUEST.value());
return; return;
} }
userInfoExample.getOredCriteria().get(0) userInfoExample.getOredCriteria().get(0)
.andUserIdIn(ownedStudentIds.isEmpty() ? Collections.singletonList("__empty__") : ownedStudentIds); .andUserIdIn(managedStudentIds.isEmpty() ? Collections.singletonList("__empty__") : managedStudentIds);
} }
List<Userinfo> list = userinfoMapper.selectByExample(userInfoExample); List<Userinfo> list = userinfoMapper.selectByExample(userInfoExample);
//导出的表名 //导出的表名
@ -1726,6 +1732,14 @@ public class UserController {
&& isClassOwner(schoolClass, operatorId); && isClassOwner(schoolClass, operatorId);
} }
private boolean canManageTeachingClass(Userinfo operator, SchoolClass teachingClass) {
return isSchoolTeacher(operator)
&& teachingClass != null
&& "TEACHING".equals(teachingClass.getClassType())
&& StringUtils.equals(operator.getSchoolId(), teachingClass.getSchoolId())
&& (isTeacherAdmin(operator) || isClassOwner(teachingClass, operator.getUserId()));
}
private boolean isClassOwner(SchoolClass schoolClass, String userId) { private boolean isClassOwner(SchoolClass schoolClass, String userId) {
return schoolClass != null return schoolClass != null
&& StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(userId)
@ -2345,6 +2359,9 @@ public class UserController {
return false; return false;
} }
SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId); SchoolClass schoolClass = schoolClassMapper.selectByPrimaryKey(schoolClassId);
if (canManageTeachingClass(operator, schoolClass)) {
return true;
}
if (canManageAdminClass(operator, schoolClass)) { if (canManageAdminClass(operator, schoolClass)) {
return true; return true;
} }

@ -201,6 +201,98 @@ class UserControllerTeacherAdminTest {
verify(controller.userinfoMapper, never()).selectByExample(any(UserinfoExample.class)); verify(controller.userinfoMapper, never()).selectByExample(any(UserinfoExample.class));
} }
@Test
void teacherAdminRosterListIncludesStudentsFromEveryTeachingClassInSchool() {
UserController controller = controllerWithCommonMocks();
SchoolClass ownedClass = classCreatedBy("teacher-admin");
ownedClass.setSchoolClassId("owned-class");
SchoolClass otherClass = classCreatedBy("teacher-2");
otherClass.setSchoolClassId("other-class");
TeachingClassStudent ownedMember = activeMember("owned-class", "student-owned");
TeachingClassStudent otherMember = activeMember("other-class", "student-other");
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-1")).thenReturn(true);
when(controller.schoolClassMapper.selectByExample(any(SchoolClassExample.class)))
.thenReturn(Arrays.asList(ownedClass, otherClass));
when(controller.teachingClassStudentMapper.selectByTeachingClassId("owned-class"))
.thenReturn(Collections.singletonList(ownedMember));
when(controller.teachingClassStudentMapper.selectByTeachingClassId("other-class"))
.thenReturn(Collections.singletonList(otherMember));
when(controller.userinfoMapper.selectByExample(any(UserinfoExample.class)))
.thenReturn(Arrays.asList(student("student-owned", "owned", "s001", null),
student("student-other", "other", "s002", null)));
ResultEntity<PageInfo<Userinfo>> result = controller.selectStudent(
"other-school", null, null, null, 1, 10, "teacher-admin");
ArgumentCaptor<UserinfoExample> exampleCaptor = ArgumentCaptor.forClass(UserinfoExample.class);
verify(controller.userinfoMapper).selectByExample(exampleCaptor.capture());
verify(controller.schoolClassMapper).selectByExample(argThat(example ->
hasCondition(example, "school_id =")
&& hasCondition(example, "class_type =")
&& !hasCondition(example, "created_by =")));
assertEquals(HttpStatus.OK, result.getStatusCode());
assertTrue(hasUserCondition(exampleCaptor.getValue(), "school_id =", "school-1"));
assertTrue(hasUserCondition(exampleCaptor.getValue(), "user_id in",
Arrays.asList("student-owned", "student-other")));
}
@Test
void teacherAdminCanUpdateStudentInAnotherTeachersTeachingClass() {
UserController controller = controllerWithCommonMocks();
SchoolClass otherClass = classCreatedBy("teacher-2");
otherClass.setSchoolClassId("other-class");
Userinfo existingStudent = student("student-other", "before", "s002", null);
when(controller.schoolProductConfigService.isTeacherRosterManaged("school-1")).thenReturn(true);
when(controller.userinfoMapper.selectByPrimaryKey("student-other")).thenReturn(existingStudent);
when(controller.schoolClassMapper.selectByPrimaryKey("other-class")).thenReturn(otherClass);
when(controller.userinfoMapper.updateByPrimaryKeySelective(any(Userinfo.class))).thenReturn(1);
ResultEntity result = controller.updateTeacherRosterStudent(
"student-other", "after", "s002", "other-class", "teacher-admin");
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.userinfoMapper).updateByPrimaryKeySelective(any(Userinfo.class));
}
@Test
void teacherAdminCanDeleteAndResetPasswordForStudentInAnotherTeachersTeachingClass() {
UserController controller = controllerWithCommonMocks();
SchoolClass otherClass = classCreatedBy("teacher-2");
otherClass.setSchoolClassId("other-class");
Userinfo existingStudent = student("student-other", "other", "s002", null);
when(controller.userinfoMapper.selectByPrimaryKey("student-other")).thenReturn(existingStudent);
when(controller.schoolClassMapper.selectByPrimaryKey("other-class")).thenReturn(otherClass);
when(controller.teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId("student-other", "other-class"))
.thenReturn(1L);
when(controller.teachingClassStudentMapper.deleteByStudentUserIdAndTeachingClassId("student-other", "other-class"))
.thenReturn(1);
when(controller.userinfoMapper.updateByPrimaryKey(existingStudent)).thenReturn(1);
ResultEntity deleteResult = controller.deleteStudent("student-other", "teacher-admin", "other-class");
ResultEntity passwordResult = controller.updateStudentPassword("student-other", "teacher-admin", "other-class");
assertEquals(HttpStatus.OK, deleteResult.getStatusCode());
assertEquals(HttpStatus.OK, passwordResult.getStatusCode());
verify(controller.teachingClassStudentMapper).deleteByStudentUserIdAndTeachingClassId("student-other", "other-class");
verify(controller.userinfoMapper).updateByPrimaryKey(existingStudent);
}
@Test
void teacherAdminCanInitializeStudentDataInAnotherTeachersTeachingClass() {
UserController controller = controllerWithCommonMocks();
SchoolClass otherClass = classCreatedBy("teacher-2");
otherClass.setSchoolClassId("other-class");
when(controller.schoolClassMapper.selectByPrimaryKey("other-class")).thenReturn(otherClass);
when(controller.teachingClassStudentMapper.countByStudentUserIdAndTeachingClassId("student-other", "other-class"))
.thenReturn(1L);
ResultEntity result = controller.initializeTeachingClassStudentTrainingData(
"other-class", "student-other", "teacher-admin");
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(controller.cptfController).restartByUserId("student-other");
}
@Test @Test
void addSchoolClassStoresCreatorTeacher() { void addSchoolClassStoresCreatorTeacher() {
UserController controller = controllerWithCommonMocks(); UserController controller = controllerWithCommonMocks();
@ -1234,6 +1326,14 @@ class UserControllerTeacherAdminTest {
return row; return row;
} }
private TeachingClassStudent activeMember(String teachingClassId, String studentUserId) {
TeachingClassStudent member = new TeachingClassStudent();
member.setTeachingClassId(teachingClassId);
member.setStudentUserId(studentUserId);
member.setStatus("IN_PROGRESS");
return member;
}
private Userinfo student(String userId, String name, String userName, String adminClassId) { private Userinfo student(String userId, String name, String userName, String adminClassId) {
Userinfo student = new Userinfo(); Userinfo student = new Userinfo();
student.setUserId(userId); student.setUserId(userId);

Loading…
Cancel
Save