feat: add commands for managing organizations and users

Introduce `AddUserToOrganization`, `RemoveAPIKey`, and 
`RemoveOrganization` commands to enhance organization 
management. Implement validation for user addition and 
API key removal. Update GraphQL schema to support new 
mutations and add caching for the new events, ensuring 
that organizations and their relationships are accurately 
represented in the cache.
This commit is contained in:
2025-11-22 18:37:07 +01:00
parent 335a9f3b54
commit ffcf41b85a
14 changed files with 1500 additions and 30 deletions
+104 -4
View File
@@ -427,7 +427,10 @@ func TestAuthMiddleware_Directive_RequiresBoth(t *testing.T) {
Name: "Test Org",
}
// Test with both present
// When both user and organization are marked as acceptable,
// the directive uses OR logic - either one is sufficient
// Test with both present - should succeed
ctx := context.WithValue(context.Background(), UserKey, "user-123")
ctx = context.WithValue(ctx, OrganizationKey, org)
_, err := authMiddleware.Directive(ctx, nil, func(ctx context.Context) (interface{}, error) {
@@ -435,19 +438,27 @@ func TestAuthMiddleware_Directive_RequiresBoth(t *testing.T) {
}, &requireUser, &requireOrg)
assert.NoError(t, err)
// Test with only user
// Test with only user - should succeed (OR logic)
ctx = context.WithValue(context.Background(), UserKey, "user-123")
_, err = authMiddleware.Directive(ctx, nil, func(ctx context.Context) (interface{}, error) {
return "success", nil
}, &requireUser, &requireOrg)
assert.Error(t, err)
assert.NoError(t, err)
// Test with only organization
// Test with only organization - should succeed (OR logic)
ctx = context.WithValue(context.Background(), OrganizationKey, org)
_, err = authMiddleware.Directive(ctx, nil, func(ctx context.Context) (interface{}, error) {
return "success", nil
}, &requireUser, &requireOrg)
assert.NoError(t, err)
// Test with neither - should fail
ctx = context.Background()
_, err = authMiddleware.Directive(ctx, nil, func(ctx context.Context) (interface{}, error) {
return "success", nil
}, &requireUser, &requireOrg)
assert.Error(t, err)
assert.Contains(t, err.Error(), "authentication required")
}
func TestAuthMiddleware_Directive_NoRequirements(t *testing.T) {
@@ -462,3 +473,92 @@ func TestAuthMiddleware_Directive_NoRequirements(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "success", result)
}
func TestUserHasRole_WithValidRole(t *testing.T) {
// Create token with roles claim
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123",
"https://unbound.se/roles": []interface{}{"admin", "user"},
})
ctx := context.WithValue(context.Background(), mw.ContextKey{}, token)
// Test for existing role
hasRole := UserHasRole(ctx, "admin")
assert.True(t, hasRole)
hasRole = UserHasRole(ctx, "user")
assert.True(t, hasRole)
}
func TestUserHasRole_WithoutRole(t *testing.T) {
// Create token with roles claim
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123",
"https://unbound.se/roles": []interface{}{"user"},
})
ctx := context.WithValue(context.Background(), mw.ContextKey{}, token)
// Test for non-existing role
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}
func TestUserHasRole_WithoutRolesClaim(t *testing.T) {
// Create token without roles claim
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123",
})
ctx := context.WithValue(context.Background(), mw.ContextKey{}, token)
// Test should return false when roles claim is missing
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}
func TestUserHasRole_WithoutToken(t *testing.T) {
ctx := context.Background()
// Test should return false when no token in context
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}
func TestUserHasRole_WithInvalidTokenType(t *testing.T) {
// Put invalid token type in context
ctx := context.WithValue(context.Background(), mw.ContextKey{}, "not-a-token")
// Test should return false when token type is invalid
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}
func TestUserHasRole_WithInvalidRolesType(t *testing.T) {
// Create token with invalid roles type
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123",
"https://unbound.se/roles": "not-an-array",
})
ctx := context.WithValue(context.Background(), mw.ContextKey{}, token)
// Test should return false when roles type is invalid
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}
func TestUserHasRole_WithInvalidRoleElementType(t *testing.T) {
// Create token with invalid role element types
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": "user-123",
"https://unbound.se/roles": []interface{}{123, 456}, // Numbers instead of strings
})
ctx := context.WithValue(context.Background(), mw.ContextKey{}, token)
// Test should return false when role elements are not strings
hasRole := UserHasRole(ctx, "admin")
assert.False(t, hasRole)
}