diff --git a/src/Jiaowu.Api/Controllers/ExperimentGradesController.cs b/src/Jiaowu.Api/Controllers/ExperimentGradesController.cs index 5004828..81d8dd2 100644 --- a/src/Jiaowu.Api/Controllers/ExperimentGradesController.cs +++ b/src/Jiaowu.Api/Controllers/ExperimentGradesController.cs @@ -1141,8 +1141,13 @@ public sealed class ExperimentGradesController( var scope = currentUserDataScope.Current; if (scope.Scope == DataScope.All) return source; if (scope.Scope == DataScope.College) + { + if (!scope.CollegeId.HasValue) return source.Where(_ => false); + var collegeId = scope.CollegeId.Value; return source.Where(x => - x.Course!.CollegeId == scope.RestrictedCollegeId); + x.Course!.CollegeId == collegeId || + x.Teachers.Any(item => item.Teacher!.CollegeId == collegeId)); + } if (scope.IsInRole(SystemRoles.Teacher)) return source.Where(x => x.Teachers.Any(item => item.Teacher!.UserId == scope.UserId)); diff --git a/src/Jiaowu.Api/Controllers/ExperimentsController.cs b/src/Jiaowu.Api/Controllers/ExperimentsController.cs index bd4e2f6..cabed29 100644 --- a/src/Jiaowu.Api/Controllers/ExperimentsController.cs +++ b/src/Jiaowu.Api/Controllers/ExperimentsController.cs @@ -1058,6 +1058,10 @@ public sealed class ExperimentsController( .Include(x => x.ExperimentProject) .ThenInclude(x => x!.TeachingTask) .ThenInclude(x => x!.Course) + .Include(x => x.ExperimentProject) + .ThenInclude(x => x!.TeachingTask) + .ThenInclude(x => x!.Teachers) + .ThenInclude(x => x.Teacher) .Include(x => x.Instructors) .ThenInclude(x => x.Teacher) .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); @@ -1124,6 +1128,12 @@ public sealed class ExperimentsController( { var session = await db.ExperimentSessions.AsNoTracking() .Include(x => x.ExperimentProject) + .ThenInclude(x => x!.TeachingTask) + .ThenInclude(x => x!.Course) + .Include(x => x.ExperimentProject) + .ThenInclude(x => x!.TeachingTask) + .ThenInclude(x => x!.Teachers) + .ThenInclude(x => x.Teacher) .Include(x => x.Instructors) .ThenInclude(x => x.Teacher) .FirstOrDefaultAsync(x => x.Id == id, cancellationToken); @@ -1541,8 +1551,13 @@ public sealed class ExperimentsController( var scope = currentUserDataScope.Current; if (scope.Scope == DataScope.All) return source; if (scope.Scope == DataScope.College) + { + if (!scope.CollegeId.HasValue) return source.Where(_ => false); + var collegeId = scope.CollegeId.Value; return source.Where(x => - x.Course!.CollegeId == scope.RestrictedCollegeId); + x.Course!.CollegeId == collegeId || + x.Teachers.Any(item => item.Teacher!.CollegeId == collegeId)); + } if (scope.IsInRole(SystemRoles.Teacher)) return source.Where(x => x.Teachers.Any(item => @@ -1560,8 +1575,15 @@ public sealed class ExperimentsController( private bool CanManageSession(ExperimentSession session) { var scope = currentUserDataScope.Current; - if (scope.Scope is DataScope.All or DataScope.College) - return true; + if (scope.Scope == DataScope.All) return true; + if (scope.Scope == DataScope.College && scope.CollegeId.HasValue) + { + var collegeId = scope.CollegeId.Value; + var task = session.ExperimentProject?.TeachingTask; + return task?.Course?.CollegeId == collegeId || + task?.Teachers.Any(item => + item.Teacher?.CollegeId == collegeId) == true; + } return scope.IsInRole(SystemRoles.Teacher) && session.Instructors.Any(instructor => instructor.Teacher?.UserId == scope.UserId); diff --git a/tests/Jiaowu.Api.Tests/ExperimentGradesControllerTests.cs b/tests/Jiaowu.Api.Tests/ExperimentGradesControllerTests.cs index 8b00269..37435f5 100644 --- a/tests/Jiaowu.Api.Tests/ExperimentGradesControllerTests.cs +++ b/tests/Jiaowu.Api.Tests/ExperimentGradesControllerTests.cs @@ -179,10 +179,65 @@ public sealed class ExperimentGradesControllerTests Status = ExperimentProjectStatus.Published, PublishedAt = DateTime.UtcNow }; - fixture.Db.AddRange(otherCollege, otherCourse, otherTask, otherProject); + var managedCourse = new Course + { + CollegeId = otherCollege.Id, + Code = "SHARED-LAB", + Name = "跨学院管理实验", + Credits = 1, + TotalHours = 16, + PracticeHours = 16, + Nature = CourseNature.Practice, + AssessmentMethod = AssessmentMethod.Assessment + }; + var managedTask = new TeachingTask + { + AcademicTermId = fixture.Term.Id, + CourseId = managedCourse.Id, + TaskNumber = "SHARED-LAB-01", + Name = "跨学院管理实验班", + Capacity = 20, + Status = TeachingTaskStatus.Published, + Teachers = + [ + new TeachingTaskTeacher + { + TeacherId = await fixture.Db.Teachers + .Where(x => x.UserId == fixture.TeacherScope.Current.UserId) + .Select(x => x.Id) + .SingleAsync(), + IsPrimary = true + } + ] + }; + var managedProject = new ExperimentProject + { + TeachingTaskId = managedTask.Id, + Code = "SHARED-LAB", + Name = "可见的跨学院实验", + ArrangementMode = ExperimentArrangementMode.Centralized, + StartDate = fixture.Term.StartDate, + EndDate = fixture.Term.EndDate, + Status = ExperimentProjectStatus.Published, + PublishedAt = DateTime.UtcNow + }; + fixture.Db.AddRange( + otherCollege, otherCourse, otherTask, otherProject, + managedCourse, managedTask, managedProject); await fixture.Db.SaveChangesAsync(); fixture.Db.ChangeTracker.Clear(); + var schoolScope = new FixedScope(new CurrentUserScope( + Guid.NewGuid(), + "校级管理员", + null, + DataScope.All, + new HashSet([SystemRoles.AcademicAdmin]))); + var schoolPage = Assert.IsType(await fixture + .ExperimentGrades(schoolScope) + .GetManagement(null, null, null, null, 1, 10, CancellationToken.None)); + Assert.Equal(3, Property(schoolPage.Value, "Total")); + var collegeScope = new FixedScope(new CurrentUserScope( Guid.NewGuid(), "学院管理员", @@ -198,11 +253,17 @@ public sealed class ExperimentGradesControllerTests 1, 10, CancellationToken.None)); - Assert.Equal(1, Property(page.Value, "Total")); - var course = Assert.Single(Property( - page.Value, "Items").Cast()); + Assert.Equal(2, Property(page.Value, "Total")); + var courses = Property(page.Value, "Items") + .Cast() + .ToList(); + Assert.Equal(2, courses.Count); + Assert.Contains(courses, course => Property(course, "CourseCode") == "SHARED-LAB"); + Assert.DoesNotContain(courses, course => Property(course, "CourseCode") == "OTHER-LAB"); + var ownCourse = Assert.Single(courses, course => + Property(course, "CourseCode") == "CSLAB"); Assert.Equal(12, Property( - course, "Projects").Cast().Count()); + ownCourse, "Projects").Cast().Count()); var filtered = Assert.IsType(await controller.GetManagement( null,