feat(api): add space roles with delegated member removal and structure management
This commit is contained in:
1 parent
059a29a8d5
commit
1dd54243ae
12 files changed
+551
-19
No files matched your search
@@ -68,4 +68,76 @@ public sealed class WorkspaceStructureTests
|
||||
Assert.Equal(ErrorCode.Forbidden, Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceGroup(ch.Id, guest, "成员分组")).Code);
|
||||
}
|
||||
|
||||
// ───── 身份组 ─────
|
||||
private static (TestEnv Env, TestChannel Ch, Credentials Owner, Credentials Alice, Credentials Bob, Credentials Carol) RoleSpace()
|
||||
{
|
||||
var env = new TestEnv(); var ownerEp = TestEnv.Endpoint(); var ch = env.Create(ownerEp, settings: new ChannelSettings { MaxMembers = 10 });
|
||||
Credentials Join(string name) { var creds = ch.Member(TestEnv.Endpoint()) with { AccountName = name }; env.Service.Join(ch.Id, creds); return creds; }
|
||||
return (env, ch, ch.Owner(ownerEp), Join("alice"), Join("bob"), Join("carol"));
|
||||
}
|
||||
[Fact]
|
||||
public void OnlyTheOwnerManagesRolesAndMembersMustHaveJoined()
|
||||
{
|
||||
var (env, ch, owner, alice, _, _) = RoleSpace(); using var _env = env;
|
||||
var created = env.Service.CreateWorkspaceRoleResult(ch.Id, owner, "管理组", null, "管理员", "blue", [WorkspacePermission.RemoveMembers]);
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceRoleResult(ch.Id, alice, "越权", null, null, null, []));
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceRoleResult(ch.Id, owner, "坏权限", null, null, null, ["nope"]));
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceRoleResult(ch.Id, owner, "坏颜色", null, null, "pink", []));
|
||||
Assert.Throws<WebDropException>(() => env.Service.SetWorkspaceRoleMembers(ch.Id, owner, created.Role.Id, ["stranger"]));
|
||||
Assert.Throws<WebDropException>(() => env.Service.SetWorkspaceRoleMembers(ch.Id, alice, created.Role.Id, ["alice"]));
|
||||
var state = env.Service.SetWorkspaceRoleMembers(ch.Id, owner, created.Role.Id, ["Alice", "alice"]);
|
||||
var role = state.Roles.Single(r => r.Id == created.Role.Id);
|
||||
Assert.Equal("管理员", role.Suffix); Assert.Equal(["alice"], role.Members);
|
||||
// 默认的「管理组」一直在;删掉自己建的不影响它,删掉默认组后也不会再自动出现
|
||||
var remaining = env.Service.DeleteWorkspaceRole(ch.Id, owner, created.Role.Id);
|
||||
Assert.Equal(WorkspaceRole.DefaultId, Assert.Single(remaining.Roles).Id);
|
||||
Assert.Empty(env.Service.DeleteWorkspaceRole(ch.Id, owner, WorkspaceRole.DefaultId).Roles);
|
||||
Assert.Empty(env.Service.CreateWorkspaceChannel(ch.Id, owner, "再写一次", null).Roles);
|
||||
}
|
||||
[Fact]
|
||||
public void StructureStoredBeforeRolesExistedStillLoadsWithAnEmptyRoleList()
|
||||
{
|
||||
var old = System.Text.Json.JsonSerializer.Deserialize("{\"revision\":3,\"channels\":[],\"groups\":[],\"folders\":[],\"locations\":[]}", WorkspaceJson.Default.WorkspaceState)!;
|
||||
Assert.Empty(old.Roles); Assert.False(old.RolesSeeded);
|
||||
}
|
||||
[Fact]
|
||||
public void EverySpaceStartsWithADefaultAdminGroupThatCanHoldMembers()
|
||||
{
|
||||
var (env, ch, owner, alice, bob, _) = RoleSpace(); using var _env = env;
|
||||
var admin = Assert.Single(env.Service.GetWorkspace(ch.Id, owner).Roles);
|
||||
Assert.Equal(WorkspaceRole.DefaultId, admin.Id); Assert.Equal("管理组", admin.Name); Assert.Empty(admin.Members);
|
||||
Assert.Contains(WorkspacePermission.RemoveMembers, admin.Permissions); Assert.Contains(WorkspacePermission.ManageStructure, admin.Permissions);
|
||||
env.Service.SetWorkspaceRoleMembers(ch.Id, owner, admin.Id, ["alice"]);
|
||||
env.Service.RevokeInvitation(ch.Id, alice, "bob"); // 加入默认管理组即可移除成员
|
||||
Assert.Throws<WebDropException>(() => env.Service.RevokeInvitation(ch.Id, bob, "alice"));
|
||||
}
|
||||
[Fact]
|
||||
public void ARoleWithRemovePermissionCanKickOrdinaryMembersOnly()
|
||||
{
|
||||
var (env, ch, owner, alice, bob, carol) = RoleSpace(); using var _env = env;
|
||||
var peer = env.Service.CreateWorkspaceRoleResult(ch.Id, owner, "管理组", null, "管理员", "blue", [WorkspacePermission.RemoveMembers]).Role;
|
||||
env.Service.SetWorkspaceRoleMembers(ch.Id, owner, peer.Id, ["alice", "carol"]);
|
||||
Assert.Throws<WebDropException>(() => env.Service.RevokeInvitation(ch.Id, bob, "alice")); // 没有权限
|
||||
Assert.Throws<WebDropException>(() => env.Service.RevokeInvitation(ch.Id, alice, "owner")); // 不能踢空间主
|
||||
Assert.Throws<WebDropException>(() => env.Service.RevokeInvitation(ch.Id, alice, "carol")); // 不能踢同样有权限的人
|
||||
Assert.Throws<WebDropException>(() => env.Service.RevokeInvitation(ch.Id, alice, "alice")); // 不能踢自己
|
||||
env.Service.RevokeInvitation(ch.Id, alice, "bob");
|
||||
Assert.DoesNotContain(env.Service.Members(ch.Id, owner), member => member.Username == "bob");
|
||||
_ = carol;
|
||||
}
|
||||
[Fact]
|
||||
public void ARoleWithStructurePermissionManagesGroupsButCannotCreateChannels()
|
||||
{
|
||||
var (env, ch, owner, alice, bob, _) = RoleSpace(); using var _env = env;
|
||||
var role = env.Service.CreateWorkspaceRoleResult(ch.Id, owner, "整理组", "【", "整理】", "green", [WorkspacePermission.ManageStructure]).Role;
|
||||
env.Service.SetWorkspaceRoleMembers(ch.Id, owner, role.Id, ["alice"]);
|
||||
var channel = env.Service.GetWorkspace(ch.Id, owner).Channels.Single();
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceGroup(ch.Id, bob, "越权"));
|
||||
var group = env.Service.CreateWorkspaceGroup(ch.Id, alice, "项目").Groups.Single();
|
||||
env.Service.RenameWorkspaceChannel(ch.Id, alice, channel.Id, "改名");
|
||||
env.Service.GroupWorkspaceChannel(ch.Id, alice, channel.Id, group.Id);
|
||||
Assert.Empty(env.Service.DeleteWorkspaceGroup(ch.Id, alice, group.Id).Groups);
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceChannel(ch.Id, alice, "新频道", null)); // 新建频道涉及密钥,只有空间主
|
||||
Assert.Throws<WebDropException>(() => env.Service.CreateWorkspaceRoleResult(ch.Id, alice, "自封", null, null, null, []));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user