专业必修、专业选修、实践课程:由课程所属学院创建、修改、删除、发布和关闭。 公共必修、公共选修:仍由校级教务管理。 校级教务可以查看全校专业课任务,但不能代替学院维护。 超级管理员保留跨学院纠错权限。 教师分配统一要求:教师已申报该课程,并通过学院审核。 兼岗账号同时拥有校级公共课和本学院专业课职责。
201 lines
6.4 KiB
C#
201 lines
6.4 KiB
C#
using System.Security.Claims;
|
|
using Jiaowu.Api.Domain.Academic;
|
|
using Jiaowu.Api.Domain.Identity;
|
|
using Jiaowu.Api.Infrastructure.Auth;
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
namespace Jiaowu.Api.Tests;
|
|
|
|
public sealed class DataScopeTests
|
|
{
|
|
[Theory]
|
|
[InlineData(SystemRoles.Student, null, DataScope.Self)]
|
|
[InlineData(SystemRoles.Counselor, SystemRoles.Teacher, DataScope.Class)]
|
|
[InlineData(SystemRoles.CollegeAdmin, SystemRoles.Counselor, DataScope.College)]
|
|
[InlineData(SystemRoles.SuperAdmin, SystemRoles.CollegeAdmin, DataScope.All)]
|
|
[InlineData(SystemRoles.AcademicAdmin, SystemRoles.Student, DataScope.All)]
|
|
public void Resolver_UsesHighestScope(
|
|
string firstRole,
|
|
string? secondRole,
|
|
DataScope expected)
|
|
{
|
|
var roles = secondRole is null
|
|
? [firstRole]
|
|
: new[] { firstRole, secondRole };
|
|
|
|
Assert.Equal(expected, EffectiveDataScopeResolver.Resolve(roles));
|
|
}
|
|
|
|
[Fact]
|
|
public void CurrentScope_ReadsIdentityAndCollegeClaims()
|
|
{
|
|
var userId = Guid.NewGuid();
|
|
var collegeId = Guid.NewGuid();
|
|
var claims = new[]
|
|
{
|
|
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
|
new Claim(ClaimTypes.Name, "院系管理员"),
|
|
new Claim(ClaimTypes.Role, SystemRoles.CollegeAdmin),
|
|
new Claim("college_id", collegeId.ToString())
|
|
};
|
|
var accessor = new HttpContextAccessor
|
|
{
|
|
HttpContext = new DefaultHttpContext
|
|
{
|
|
User = new ClaimsPrincipal(new ClaimsIdentity(claims, "test"))
|
|
}
|
|
};
|
|
|
|
var current = new CurrentUserDataScope(accessor).Current;
|
|
|
|
Assert.Equal(userId, current.UserId);
|
|
Assert.Equal(collegeId, current.CollegeId);
|
|
Assert.Equal(DataScope.College, current.Scope);
|
|
Assert.True(current.CanAccessCollege(collegeId));
|
|
Assert.False(current.CanAccessCollege(Guid.NewGuid()));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(CourseNature.MajorRequired, true)]
|
|
[InlineData(CourseNature.MajorElective, true)]
|
|
[InlineData(CourseNature.Practice, true)]
|
|
[InlineData(CourseNature.GeneralRequired, false)]
|
|
[InlineData(CourseNature.GeneralElective, false)]
|
|
public void CollegeAdmin_OnlyMaintainsDelegatedCourseNatures(
|
|
CourseNature nature,
|
|
bool expected)
|
|
{
|
|
var collegeId = Guid.NewGuid();
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"学院教务",
|
|
collegeId,
|
|
DataScope.College,
|
|
new HashSet<string>([SystemRoles.CollegeAdmin]));
|
|
|
|
Assert.Equal(
|
|
expected,
|
|
CourseMaintenancePolicy.CanManage(scope, collegeId, nature));
|
|
Assert.False(CourseMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
nature));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(SystemRoles.SuperAdmin)]
|
|
[InlineData(SystemRoles.AcademicAdmin)]
|
|
public void SchoolAdministrators_RetainWholeCourseCatalogueManagement(string role)
|
|
{
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"校级教务",
|
|
null,
|
|
DataScope.All,
|
|
new HashSet<string>([role]));
|
|
|
|
Assert.True(CourseMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
CourseNature.GeneralRequired));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(CourseNature.MajorRequired, true)]
|
|
[InlineData(CourseNature.MajorElective, true)]
|
|
[InlineData(CourseNature.Practice, true)]
|
|
[InlineData(CourseNature.GeneralRequired, false)]
|
|
[InlineData(CourseNature.GeneralElective, false)]
|
|
public void CollegeAdmin_Manages_Own_Professional_TeachingTasks(
|
|
CourseNature nature,
|
|
bool expected)
|
|
{
|
|
var collegeId = Guid.NewGuid();
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"学院教务",
|
|
collegeId,
|
|
DataScope.College,
|
|
new HashSet<string>([SystemRoles.CollegeAdmin]));
|
|
|
|
Assert.Equal(
|
|
expected,
|
|
TeachingTaskMaintenancePolicy.CanManage(scope, collegeId, nature));
|
|
Assert.False(TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
nature));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(CourseNature.GeneralRequired, true)]
|
|
[InlineData(CourseNature.GeneralElective, true)]
|
|
[InlineData(CourseNature.MajorRequired, false)]
|
|
[InlineData(CourseNature.MajorElective, false)]
|
|
[InlineData(CourseNature.Practice, false)]
|
|
public void AcademicAdmin_Manages_Public_Not_Professional_TeachingTasks(
|
|
CourseNature nature,
|
|
bool expected)
|
|
{
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"校级教务",
|
|
null,
|
|
DataScope.All,
|
|
new HashSet<string>([SystemRoles.AcademicAdmin]));
|
|
|
|
Assert.Equal(
|
|
expected,
|
|
TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
nature));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(CourseNature.GeneralRequired)]
|
|
[InlineData(CourseNature.MajorRequired)]
|
|
[InlineData(CourseNature.Practice)]
|
|
public void SuperAdmin_Can_Override_TeachingTask_Responsibility(
|
|
CourseNature nature)
|
|
{
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"超级管理员",
|
|
null,
|
|
DataScope.All,
|
|
new HashSet<string>([SystemRoles.SuperAdmin]));
|
|
|
|
Assert.True(TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
nature));
|
|
}
|
|
|
|
[Fact]
|
|
public void Combined_School_And_College_Roles_Keep_Both_Responsibilities()
|
|
{
|
|
var collegeId = Guid.NewGuid();
|
|
var scope = new CurrentUserScope(
|
|
Guid.NewGuid(),
|
|
"校院兼岗教务",
|
|
collegeId,
|
|
DataScope.All,
|
|
new HashSet<string>(
|
|
[SystemRoles.AcademicAdmin, SystemRoles.CollegeAdmin]));
|
|
|
|
Assert.True(TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
CourseNature.GeneralRequired));
|
|
Assert.True(TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
collegeId,
|
|
CourseNature.MajorRequired));
|
|
Assert.False(TeachingTaskMaintenancePolicy.CanManage(
|
|
scope,
|
|
Guid.NewGuid(),
|
|
CourseNature.MajorRequired));
|
|
}
|
|
}
|