diff --git a/server/internal/logic/sys/im_admin_scope.go b/server/internal/logic/sys/im_admin_scope.go index a1ee539..8022642 100644 --- a/server/internal/logic/sys/im_admin_scope.go +++ b/server/internal/logic/sys/im_admin_scope.go @@ -39,7 +39,7 @@ func resolveImAdminScopeWithAll(ctx context.Context, selectedTenantId int64, all scope.OperatorId = operatorId scope.RoleKey = contexts.GetRoleKey(ctx) scope.RequestId = gctx.CtxId(ctx) - if service.AdminMember().VerifySuperId(ctx, operatorId) { + if isImPlatformAdmin(ctx, operatorId) { if selectedTenantId <= 0 { if allowAll { return scope, nil @@ -53,12 +53,12 @@ func resolveImAdminScopeWithAll(ctx context.Context, selectedTenantId int64, all return scope, nil } - if contexts.GetDeptType(ctx) != consts.DeptTypeTenant { - return scope, gerror.New("当前账号不是租户管理员,不能管理邀请码") + if !contexts.IsTenantDept(ctx) { + return scope, gerror.New("当前账号无权管理IM租户") } - tenantId := contexts.GetTenantId(ctx) - if tenantId <= 0 { - return scope, gerror.New("当前管理员未关联租户") + tenantId, err := resolveImAdminBoundTenant(ctx) + if err != nil { + return scope, err } if err = ensureImTenantActive(ctx, tenantId); err != nil { return scope, err @@ -67,6 +67,21 @@ func resolveImAdminScopeWithAll(ctx context.Context, selectedTenantId int64, all return scope, nil } +func isImPlatformAdmin(ctx context.Context, operatorId int64) bool { + if contexts.IsCompanyDept(ctx) { + return true + } + return service.AdminMember().VerifySuperId(ctx, operatorId) +} + +func resolveImAdminBoundTenant(ctx context.Context) (int64, error) { + tenantId := contexts.GetTenantId(ctx) + if tenantId <= 0 { + return 0, gerror.New("当前管理员未关联IM租户") + } + return tenantId, nil +} + func ensureImTenantActive(ctx context.Context, tenantId int64) (err error) { var tenant *entity.ImTenant if err = imtenant.RegistryDB().Model(dao.ImTenant.Table()).Safe().Ctx(ctx).WherePri(tenantId).Scan(&tenant); err != nil { diff --git a/server/internal/logic/sys/im_admin_scope_test.go b/server/internal/logic/sys/im_admin_scope_test.go new file mode 100644 index 0000000..4b8e97d --- /dev/null +++ b/server/internal/logic/sys/im_admin_scope_test.go @@ -0,0 +1,57 @@ +package sys + +import ( + "context" + "testing" + + "hotgo/internal/consts" + "hotgo/internal/model" +) + +func TestCompanyDepartmentIsImPlatformAdmin(t *testing.T) { + ctx := context.WithValue(context.Background(), consts.ContextHTTPKey, &model.Context{ + User: &model.Identity{Id: 14, TenantId: 1, DeptType: consts.DeptTypeCompany, RoleKey: "imManage"}, + }) + if !isImPlatformAdmin(ctx, 14) { + t.Fatal("expected company department IM manager to use platform tenant selection") + } +} + +func TestResolveImAdminBoundTenant(t *testing.T) { + tests := []struct { + name string + identity *model.Identity + want int64 + }{ + { + name: "tenant department with tenant binding", + identity: &model.Identity{ + TenantId: 2, + DeptType: consts.DeptTypeTenant, + }, + want: 2, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), consts.ContextHTTPKey, &model.Context{User: tt.identity}) + got, err := resolveImAdminBoundTenant(ctx) + if err != nil { + t.Fatal(err) + } + if got != tt.want { + t.Fatalf("tenant binding mismatch: got %d, want %d", got, tt.want) + } + }) + } +} + +func TestResolveImAdminBoundTenantRejectsUnboundAccount(t *testing.T) { + ctx := context.WithValue(context.Background(), consts.ContextHTTPKey, &model.Context{ + User: &model.Identity{DeptType: consts.DeptTypeTenant, RoleKey: "tenantManager"}, + }) + if _, err := resolveImAdminBoundTenant(ctx); err == nil { + t.Fatal("expected unbound account to be rejected") + } +}