Include personally enrolled courses in student course listings
This commit is contained in:
1 parent
852668f0e5
commit
3b1b1f3c88
2 files changed
+99
-5
No files matched your search
@@ -340,11 +340,17 @@ public sealed class CoursesController(
|
|||||||
isTeacher && db.TeachingTasks.Any(task =>
|
isTeacher && db.TeachingTasks.Any(task =>
|
||||||
task.CourseId == course.Id &&
|
task.CourseId == course.Id &&
|
||||||
task.Teachers.Any(item => item.Teacher!.UserId == userId)) ||
|
task.Teachers.Any(item => item.Teacher!.UserId == userId)) ||
|
||||||
isStudent && db.TeachingTasks.Any(task =>
|
isStudent && (
|
||||||
task.CourseId == course.Id &&
|
db.TeachingTasks.Any(task =>
|
||||||
task.Classes.Any(item =>
|
task.CourseId == course.Id &&
|
||||||
item.AdministrativeClass!.Students.Any(student =>
|
task.Classes.Any(item =>
|
||||||
student.UserId == userId))));
|
item.AdministrativeClass!.Students.Any(student =>
|
||||||
|
student.UserId == userId))) ||
|
||||||
|
db.CourseEnrollments.Any(enrollment =>
|
||||||
|
enrollment.Status == CourseEnrollmentStatus.Enrolled &&
|
||||||
|
enrollment.Student!.UserId == userId &&
|
||||||
|
enrollment.CourseSelectionOffering!.TeachingTask!.CourseId ==
|
||||||
|
course.Id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CanManage(Guid collegeId, CourseNature nature)
|
private bool CanManage(Guid collegeId, CourseNature nature)
|
||||||
|
|||||||
@@ -101,6 +101,84 @@ public sealed class CoursesControllerTests
|
|||||||
Assert.Contains("OTHER-001", courses);
|
Assert.Contains("OTHER-001", courses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Student_Get_IncludesCourseFromActivePersonalEnrollment()
|
||||||
|
{
|
||||||
|
await using var connection = new SqliteConnection("Data Source=:memory:");
|
||||||
|
await connection.OpenAsync();
|
||||||
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseSqlite(connection)
|
||||||
|
.Options;
|
||||||
|
await using var db = new AppDbContext(options);
|
||||||
|
await db.Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
var studentUserId = Guid.NewGuid();
|
||||||
|
var college = new College { Code = "CS", Name = "计算机学院" };
|
||||||
|
var major = new Major
|
||||||
|
{
|
||||||
|
Code = "CS01", Name = "软件工程", CollegeId = college.Id, DegreeType = "本科"
|
||||||
|
};
|
||||||
|
var administrativeClass = new AdministrativeClass
|
||||||
|
{
|
||||||
|
Code = "SE2601", Name = "软件 2601", MajorId = major.Id, Grade = 2026
|
||||||
|
};
|
||||||
|
var student = new Student
|
||||||
|
{
|
||||||
|
StudentNumber = "20260001", Name = "测试学生", UserId = studentUserId,
|
||||||
|
AdministrativeClassId = administrativeClass.Id,
|
||||||
|
EnrollmentDate = new DateOnly(2026, 9, 1)
|
||||||
|
};
|
||||||
|
var category = new CourseCategory { Code = "CORE", Name = "核心课程" };
|
||||||
|
var selectedCourse = new Course
|
||||||
|
{
|
||||||
|
Code = "CS102", Name = "数据结构", CollegeId = college.Id,
|
||||||
|
CourseCategoryId = category.Id, Nature = CourseNature.MajorElective,
|
||||||
|
Credits = 3, TotalHours = 48, IsEnabled = true
|
||||||
|
};
|
||||||
|
var term = new AcademicTerm
|
||||||
|
{
|
||||||
|
Code = "2026-1", Name = "2026-2027-1", AcademicYear = "2026-2027",
|
||||||
|
Season = TermSeason.Autumn, StartDate = new DateOnly(2026, 9, 1),
|
||||||
|
EndDate = new DateOnly(2027, 1, 31), IsCurrent = true
|
||||||
|
};
|
||||||
|
var task = new TeachingTask
|
||||||
|
{
|
||||||
|
TaskNumber = "T-CS102", Name = "数据结构选课班", AcademicTermId = term.Id,
|
||||||
|
CourseId = selectedCourse.Id, Capacity = 50, Status = TeachingTaskStatus.Published
|
||||||
|
};
|
||||||
|
var round = new CourseSelectionRound
|
||||||
|
{
|
||||||
|
AcademicTermId = term.Id, Name = "第一轮", StartsAt = DateTime.UtcNow,
|
||||||
|
EndsAt = DateTime.UtcNow.AddDays(1), WithdrawalEndsAt = DateTime.UtcNow.AddDays(2)
|
||||||
|
};
|
||||||
|
var offering = new CourseSelectionOffering
|
||||||
|
{
|
||||||
|
CourseSelectionRoundId = round.Id, TeachingTaskId = task.Id, Capacity = 50
|
||||||
|
};
|
||||||
|
db.AddRange(college, major, administrativeClass, student, category, selectedCourse,
|
||||||
|
new ApplicationUser
|
||||||
|
{
|
||||||
|
Id = studentUserId, UserName = "20260001", DisplayName = "测试学生"
|
||||||
|
},
|
||||||
|
term, task, round, offering,
|
||||||
|
new CourseEnrollment
|
||||||
|
{
|
||||||
|
CourseSelectionOfferingId = offering.Id, StudentId = student.Id,
|
||||||
|
Status = CourseEnrollmentStatus.Enrolled
|
||||||
|
});
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
var controller = new CoursesController(
|
||||||
|
db, new StudentDataScope(studentUserId), NoOpAppCache.Instance);
|
||||||
|
|
||||||
|
var result = await controller.Get(cancellationToken: CancellationToken.None);
|
||||||
|
|
||||||
|
var ok = Assert.IsType<OkObjectResult>(result.Result);
|
||||||
|
var page = Assert.IsType<PagedResult<object>>(ok.Value);
|
||||||
|
Assert.Equal(1, page.Total);
|
||||||
|
Assert.Contains("CS102", JsonSerializer.Serialize(page.Items));
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class TestDataScope(Guid collegeId) : ICurrentUserDataScope
|
private sealed class TestDataScope(Guid collegeId) : ICurrentUserDataScope
|
||||||
{
|
{
|
||||||
public CurrentUserScope Current { get; } = new(
|
public CurrentUserScope Current { get; } = new(
|
||||||
@@ -110,4 +188,14 @@ public sealed class CoursesControllerTests
|
|||||||
DataScope.College,
|
DataScope.College,
|
||||||
new HashSet<string>([SystemRoles.CollegeAdmin]));
|
new HashSet<string>([SystemRoles.CollegeAdmin]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class StudentDataScope(Guid userId) : ICurrentUserDataScope
|
||||||
|
{
|
||||||
|
public CurrentUserScope Current { get; } = new(
|
||||||
|
userId,
|
||||||
|
"测试学生",
|
||||||
|
null,
|
||||||
|
DataScope.Self,
|
||||||
|
new HashSet<string>([SystemRoles.Student]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user