Skip to content

Commit e5ec668

Browse files
feat: update GetEntityInfo200Response and User schemas to include id and roles
1 parent feaf4b0 commit e5ec668

12 files changed

Lines changed: 310 additions & 36 deletions

File tree

mocks/user.fixtures.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {User, UserSummary} from "../generated/openapi/model/models"
2+
import {MOCK_GROUP_ID} from "./group.fixtures"
23

34
export const MOCK_USER_ID = "e6e08687-2189-4710-91b5-479cd25a9119"
45
export const MOCK_ADMIN_USER_ID = "2d099b40-099f-4975-9320-e52aacfaccd6"
@@ -8,19 +9,48 @@ export const memberUserResponse: User = {
89
displayName: "Test User",
910
email: "test@localhost.com",
1011
orgRole: "member",
11-
createdAt: "2026-03-08T12:00:00Z"
12+
createdAt: "2026-03-08T12:00:00Z",
13+
groups: [],
14+
roles: [],
15+
concurrencyControl: {version: "1"}
1216
}
1317

1418
export const adminUserResponse: User = {
1519
id: MOCK_ADMIN_USER_ID,
1620
displayName: "Admin User",
1721
email: "admin@localhost.com",
1822
orgRole: "admin",
19-
createdAt: "2026-03-08T12:00:00Z"
23+
createdAt: "2026-03-08T12:00:00Z",
24+
groups: [],
25+
roles: [],
26+
concurrencyControl: {version: "1"}
2027
}
2128

2229
export const userSummaryResponse: UserSummary = {
2330
id: memberUserResponse.id,
2431
displayName: memberUserResponse.displayName,
2532
email: memberUserResponse.email
2633
}
34+
35+
export const userWithGroupsAndRolesResponse: User = {
36+
id: "f3c8b4df-6d75-4309-844a-9c7efc8bf141",
37+
displayName: "User with Groups and Roles",
38+
email: "groups-roles@localhost.com",
39+
orgRole: "member",
40+
createdAt: "2026-03-08T12:00:00Z",
41+
groups: [
42+
{
43+
groupId: MOCK_GROUP_ID,
44+
groupName: "Engineering Team"
45+
}
46+
],
47+
roles: [
48+
{
49+
roleName: "SpaceManager",
50+
scope: {
51+
type: "org"
52+
}
53+
}
54+
],
55+
concurrencyControl: {version: "1"}
56+
}

openapi.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ openapi: 3.0.0
22
info:
33
title: Workflow Approval System API
44
description: API for a SaaS platform that allows customers to manage approvals for generic workflows, users, and groups.
5-
version: 0.0.40
5+
version: 0.0.41
66
tags:
77
- name: Authentication
88
description: OIDC authentication and token management

openapi/auth/auth-info.yaml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,6 @@ get:
1010
content:
1111
application/json:
1212
schema:
13-
type: object
14-
required:
15-
- entityType
16-
- groups
17-
properties:
18-
entityType:
19-
type: string
20-
description: Type of the authenticated entity
21-
example: user
22-
groups:
23-
type: array
24-
items:
25-
$ref: ../groups/schemas.yaml#/GroupInfo
13+
$ref: ./schemas.yaml#/GetEntityInfo200Response
2614
"401":
2715
$ref: ../shared/responses.yaml#/Unauthorized

openapi/auth/schemas.yaml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,75 @@ PrivilegedTokenExchangeRequest:
7070
description: The identifier of the resource being accessed
7171
operation:
7272
$ref: ../shared/schemas.yaml#/PrivilegedOperation
73+
74+
GetEntityInfo200Response:
75+
description: Entity information response based on the authenticated entity type.
76+
oneOf:
77+
- $ref: "#/GetEntityInfoUserResponse"
78+
- $ref: "#/GetEntityInfoAgentResponse"
79+
discriminator:
80+
propertyName: entityType
81+
mapping:
82+
user: "#/GetEntityInfoUserResponse"
83+
agent: "#/GetEntityInfoAgentResponse"
84+
85+
GetEntityInfoUserResponse:
86+
type: object
87+
required:
88+
- id
89+
- entityType
90+
- groups
91+
- roles
92+
- orgRole
93+
properties:
94+
id:
95+
type: string
96+
format: uuid
97+
description: Internal unique identifier for the user.
98+
entityType:
99+
type: string
100+
enum:
101+
- user
102+
description: Type of the authenticated entity
103+
example: user
104+
groups:
105+
type: array
106+
items:
107+
$ref: ../groups/schemas.yaml#/GroupInfo
108+
roles:
109+
type: array
110+
items:
111+
$ref: ../roles/schemas.yaml#/RoleOperationItem
112+
orgRole:
113+
type: string
114+
enum:
115+
- admin
116+
- member
117+
description: Role assigned to the user within the organization.
118+
119+
GetEntityInfoAgentResponse:
120+
type: object
121+
required:
122+
- id
123+
- entityType
124+
- groups
125+
- roles
126+
properties:
127+
id:
128+
type: string
129+
format: uuid
130+
description: Internal unique identifier for the agent.
131+
entityType:
132+
type: string
133+
enum:
134+
- agent
135+
description: Type of the authenticated entity
136+
example: agent
137+
groups:
138+
type: array
139+
items:
140+
$ref: ../groups/schemas.yaml#/GroupInfo
141+
roles:
142+
type: array
143+
items:
144+
$ref: ../roles/schemas.yaml#/RoleOperationItem

openapi/roles/schemas.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ RoleOperationRequest: &ref_0
6060
description: Request to assign or remove roles from a user or agent
6161
required:
6262
- roles
63+
- concurrencyControl
6364
properties:
6465
roles:
6566
type: array
@@ -71,5 +72,7 @@ RoleOperationRequest: &ref_0
7172
scope:
7273
type: group
7374
groupId: a1b2c3d4-e5f6-7890-1234-567890abcdef
75+
concurrencyControl:
76+
$ref: ../shared/schemas.yaml#/ConcurrencyControl
7477
RoleAssignmentRequest: *ref_0
7578
RoleRemovalRequest: *ref_0

openapi/users/schemas.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ User:
5151
- email
5252
- orgRole
5353
- createdAt
54+
- groups
55+
- roles
56+
- concurrencyControl
5457
properties:
5558
id:
5659
type: string
@@ -74,12 +77,22 @@ User:
7477
- member
7578
description: Role assigned to the user within the organization.
7679
example: member
80+
groups:
81+
type: array
82+
items:
83+
$ref: ../groups/schemas.yaml#/GroupInfo
84+
roles:
85+
type: array
86+
items:
87+
$ref: ../roles/schemas.yaml#/RoleOperationItem
7788
createdAt:
7889
type: string
7990
format: date-time
8091
description: Timestamp when the user was created.
8192
readOnly: true
8293
example: "2025-04-15T12:05:00Z"
94+
concurrencyControl:
95+
$ref: ../shared/schemas.yaml#/ConcurrencyControl
8396
ListUsersParams:
8497
type: object
8598
properties:

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@approvio/api",
33
"author": "Giovanni Baratta",
44
"license": "MIT",
5-
"version": "0.0.46",
5+
"version": "0.0.47",
66
"private": false,
77
"type": "module",
88
"main": "./dist/src/index.cjs",
@@ -71,4 +71,4 @@
7171
"peerDependencies": {
7272
"fp-ts": "^2.0.0"
7373
}
74-
}
74+
}

src/validators/common.validators.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import {Either, left, right, isLeft} from "fp-ts/Either"
2-
import {hasOwnProperty, isNumber, isNonEmptyString, isArray} from "../utils/validation.utils"
3-
import {Pagination, HealthResponse, GetEntityInfo200Response, GroupInfo} from "../../generated/openapi/model/models"
2+
import {hasOwnProperty, isNumber, isNonEmptyString, isArray, isUUIDv4} from "../utils/validation.utils"
3+
import {
4+
Pagination,
5+
HealthResponse,
6+
GetEntityInfo200Response,
7+
GroupInfo,
8+
RoleOperationItem
9+
} from "../../generated/openapi/model/models"
410
import {validateGroupInfo} from "./groups.validators"
11+
import {validateRoleOperationItem} from "./users.validators"
512

613
export type PaginationValidationError =
714
| "malformed_object"
@@ -104,6 +111,12 @@ export type GetEntityInfo200ResponseValidationError =
104111
| "invalid_entity_type"
105112
| "missing_groups"
106113
| "invalid_groups"
114+
| "missing_id"
115+
| "invalid_id"
116+
| "missing_roles"
117+
| "invalid_roles"
118+
| "missing_org_role"
119+
| "invalid_org_role"
107120

108121
export function validateGetEntityInfo200Response(
109122
object: unknown
@@ -113,6 +126,9 @@ export function validateGetEntityInfo200Response(
113126
if (!hasOwnProperty(object, "entityType") || !isNonEmptyString(object.entityType))
114127
return left(hasOwnProperty(object, "entityType") ? "invalid_entity_type" : "missing_entity_type")
115128

129+
if (!hasOwnProperty(object, "id")) return left("missing_id")
130+
if (!isNonEmptyString(object.id) || !isUUIDv4(object.id)) return left("invalid_id")
131+
116132
if (!hasOwnProperty(object, "groups") || !isArray(object.groups))
117133
return left(hasOwnProperty(object, "groups") ? "invalid_groups" : "missing_groups")
118134

@@ -123,8 +139,35 @@ export function validateGetEntityInfo200Response(
123139
groups.push(validatedItem.right)
124140
}
125141

126-
return right({
127-
entityType: object.entityType,
128-
groups
129-
})
142+
if (!hasOwnProperty(object, "roles")) return left("missing_roles")
143+
if (!isArray(object.roles)) return left("invalid_roles")
144+
145+
const roles: RoleOperationItem[] = []
146+
for (const role of object.roles) {
147+
const validatedRole = validateRoleOperationItem(role)
148+
if (isLeft(validatedRole)) return left("invalid_roles")
149+
roles.push(validatedRole.right)
150+
}
151+
152+
if (object.entityType === "user") {
153+
if (!hasOwnProperty(object, "orgRole")) return left("missing_org_role")
154+
if (object.orgRole !== "admin" && object.orgRole !== "member") return left("invalid_org_role")
155+
156+
return right({
157+
entityType: "user" as const,
158+
id: object.id,
159+
groups,
160+
roles,
161+
orgRole: object.orgRole
162+
})
163+
} else if (object.entityType === "agent") {
164+
return right({
165+
entityType: "agent" as const,
166+
id: object.id,
167+
groups,
168+
roles
169+
})
170+
}
171+
172+
return left("invalid_entity_type")
130173
}

0 commit comments

Comments
 (0)