Skip to content

Commit 9ad9930

Browse files
author
Lasim
committed
refactor: enhance team API and frontend to include user role information and member count
1 parent 9015e3b commit 9ad9930

6 files changed

Lines changed: 155 additions & 106 deletions

File tree

services/backend/api-spec.json

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4541,16 +4541,10 @@
45414541
"pattern": "^[a-zA-Z0-9._-]+$"
45424542
},
45434543
"value": {
4544-
"oneOf": [
4545-
{
4546-
"type": "string"
4547-
},
4548-
{
4549-
"type": "number"
4550-
},
4551-
{
4552-
"type": "boolean"
4553-
}
4544+
"type": [
4545+
"string",
4546+
"number",
4547+
"boolean"
45544548
]
45554549
},
45564550
"type": {
@@ -5812,16 +5806,10 @@
58125806
"pattern": "^[a-zA-Z0-9._-]+$"
58135807
},
58145808
"value": {
5815-
"oneOf": [
5816-
{
5817-
"type": "string"
5818-
},
5819-
{
5820-
"type": "number"
5821-
},
5822-
{
5823-
"type": "boolean"
5824-
}
5809+
"type": [
5810+
"string",
5811+
"number",
5812+
"boolean"
58255813
]
58265814
},
58275815
"type": {
@@ -7677,11 +7665,11 @@
76777665
},
76787666
"/api/teams/{id}": {
76797667
"get": {
7680-
"summary": "Get team by ID",
7668+
"summary": "Get team by ID with user role",
76817669
"tags": [
76827670
"Teams"
76837671
],
7684-
"description": "Retrieves a specific team by its ID. User must be a member of the team.",
7672+
"description": "Retrieves a specific team by its ID with the current user's role and permissions within that team. User must be a member of the team.",
76857673
"parameters": [
76867674
{
76877675
"schema": {
@@ -7704,15 +7692,15 @@
77047692
"application/json": {
77057693
"schema": {
77067694
"schema": {
7707-
"description": "Team retrieved successfully",
7695+
"description": "Team retrieved successfully with user role info",
77087696
"type": "object",
77097697
"properties": {
77107698
"success": {
77117699
"description": "Indicates if the operation was successful",
77127700
"type": "boolean"
77137701
},
77147702
"data": {
7715-
"description": "Team data",
7703+
"description": "Team data with user role information",
77167704
"type": "object",
77177705
"properties": {
77187706
"id": {
@@ -7753,6 +7741,26 @@
77537741
"updated_at": {
77547742
"description": "Team last update date",
77557743
"type": "string"
7744+
},
7745+
"role": {
7746+
"description": "User role in the team",
7747+
"type": "string",
7748+
"enum": [
7749+
"team_admin",
7750+
"team_user"
7751+
]
7752+
},
7753+
"is_admin": {
7754+
"description": "True if user is team admin",
7755+
"type": "boolean"
7756+
},
7757+
"is_owner": {
7758+
"description": "True if user is team owner",
7759+
"type": "boolean"
7760+
},
7761+
"member_count": {
7762+
"description": "Total number of team members",
7763+
"type": "number"
77567764
}
77577765
},
77587766
"required": [
@@ -7763,13 +7771,13 @@
77637771
"owner_id",
77647772
"is_default",
77657773
"created_at",
7766-
"updated_at"
7774+
"updated_at",
7775+
"role",
7776+
"is_admin",
7777+
"is_owner",
7778+
"member_count"
77677779
],
77687780
"additionalProperties": false
7769-
},
7770-
"message": {
7771-
"description": "Success message",
7772-
"type": "string"
77737781
}
77747782
},
77757783
"required": [
@@ -14495,7 +14503,6 @@
1449514503
},
1449614504
"tools": {
1449714505
"type": "array",
14498-
"minItems": 1,
1449914506
"items": {
1450014507
"type": "object",
1450114508
"properties": {
@@ -14607,8 +14614,7 @@
1460714614
"description",
1460814615
"language",
1460914616
"runtime",
14610-
"claude_desktop_config",
14611-
"tools"
14617+
"claude_desktop_config"
1461214618
],
1461314619
"additionalProperties": false
1461414620
}

services/backend/api-spec.yaml

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,10 +3085,10 @@ paths:
30853085
maxLength: 255
30863086
pattern: ^[a-zA-Z0-9._-]+$
30873087
value:
3088-
oneOf:
3089-
- type: string
3090-
- type: number
3091-
- type: boolean
3088+
type:
3089+
- string
3090+
- number
3091+
- boolean
30923092
type:
30933093
type: string
30943094
enum:
@@ -3966,10 +3966,10 @@ paths:
39663966
maxLength: 255
39673967
pattern: ^[a-zA-Z0-9._-]+$
39683968
value:
3969-
oneOf:
3970-
- type: string
3971-
- type: number
3972-
- type: boolean
3969+
type:
3970+
- string
3971+
- number
3972+
- boolean
39733973
type:
39743974
type: string
39753975
enum:
@@ -5267,10 +5267,11 @@ paths:
52675267
components: {}
52685268
/api/teams/{id}:
52695269
get:
5270-
summary: Get team by ID
5270+
summary: Get team by ID with user role
52715271
tags:
52725272
- Teams
5273-
description: Retrieves a specific team by its ID. User must be a member of the team.
5273+
description: Retrieves a specific team by its ID with the current user's role
5274+
and permissions within that team. User must be a member of the team.
52745275
parameters:
52755276
- schema:
52765277
type: string
@@ -5286,14 +5287,14 @@ paths:
52865287
application/json:
52875288
schema:
52885289
schema:
5289-
description: Team retrieved successfully
5290+
description: Team retrieved successfully with user role info
52905291
type: object
52915292
properties:
52925293
success:
52935294
description: Indicates if the operation was successful
52945295
type: boolean
52955296
data:
5296-
description: Team data
5297+
description: Team data with user role information
52975298
type: object
52985299
properties:
52995300
id:
@@ -5322,6 +5323,21 @@ paths:
53225323
updated_at:
53235324
description: Team last update date
53245325
type: string
5326+
role:
5327+
description: User role in the team
5328+
type: string
5329+
enum:
5330+
- team_admin
5331+
- team_user
5332+
is_admin:
5333+
description: True if user is team admin
5334+
type: boolean
5335+
is_owner:
5336+
description: True if user is team owner
5337+
type: boolean
5338+
member_count:
5339+
description: Total number of team members
5340+
type: number
53255341
required:
53265342
- id
53275343
- name
@@ -5331,10 +5347,11 @@ paths:
53315347
- is_default
53325348
- created_at
53335349
- updated_at
5350+
- role
5351+
- is_admin
5352+
- is_owner
5353+
- member_count
53345354
additionalProperties: false
5335-
message:
5336-
description: Success message
5337-
type: string
53385355
required:
53395356
- success
53405357
- data
@@ -9834,7 +9851,6 @@ paths:
98349851
additionalProperties: false
98359852
tools:
98369853
type: array
9837-
minItems: 1
98389854
items:
98399855
type: object
98409856
properties:
@@ -9914,7 +9930,6 @@ paths:
99149930
- language
99159931
- runtime
99169932
- claude_desktop_config
9917-
- tools
99189933
additionalProperties: false
99199934
required: true
99209935
security:

services/backend/src/routes/teams/index.ts

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
2-
import { ZodError } from 'zod';
2+
import { ZodError, z } from 'zod';
33
import { createSchema } from 'zod-openapi';
44
import { TeamService } from '../../services/teamService';
55
import { requirePermission, checkUserPermission } from '../../middleware/roleMiddleware';
@@ -15,6 +15,7 @@ import {
1515
TransferOwnershipSchema,
1616
SuccessResponseSchema,
1717
ErrorResponseSchema,
18+
TeamWithRoleInfoSchema,
1819
type CreateTeamInput,
1920
type UpdateTeamInput,
2021
type AddTeamMemberInput,
@@ -106,12 +107,12 @@ export default async function teamsRoute(fastify: FastifyInstance) {
106107
}
107108
});
108109

109-
// GET /teams/:id - Get team by ID
110+
// GET /teams/:id - Get team by ID with user role info
110111
fastify.get<{ Params: { id: string } }>('/teams/:id', {
111112
schema: {
112113
tags: ['Teams'],
113-
summary: 'Get team by ID',
114-
description: 'Retrieves a specific team by its ID. User must be a member of the team.',
114+
summary: 'Get team by ID with user role',
115+
description: 'Retrieves a specific team by its ID with the current user\'s role and permissions within that team. User must be a member of the team.',
115116
security: [{ cookieAuth: [] }],
116117
params: {
117118
type: 'object',
@@ -121,7 +122,10 @@ export default async function teamsRoute(fastify: FastifyInstance) {
121122
required: ['id']
122123
},
123124
response: {
124-
200: createSchema(TeamResponseSchema.describe('Team retrieved successfully')),
125+
200: createSchema(z.object({
126+
success: z.boolean().describe('Indicates if the operation was successful'),
127+
data: TeamWithRoleInfoSchema.describe('Team data with user role information')
128+
}).describe('Team retrieved successfully with user role info')),
125129
401: createSchema(ErrorResponseSchema.describe('Unauthorized - Authentication required')),
126130
403: createSchema(ErrorResponseSchema.describe('Forbidden - Insufficient permissions')),
127131
404: createSchema(ErrorResponseSchema.describe('Not Found - Team not found')),
@@ -131,42 +135,65 @@ export default async function teamsRoute(fastify: FastifyInstance) {
131135
}, async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) => {
132136
try {
133137
if (!request.user) {
134-
return reply.status(401).send({
138+
const errorResponse = {
135139
success: false,
136-
error: 'Authentication required',
137-
});
140+
error: 'Authentication required'
141+
};
142+
const jsonString = JSON.stringify(errorResponse);
143+
return reply.status(401).type('application/json').send(jsonString);
138144
}
139145

140146
const teamId = request.params.id;
141147
const team = await TeamService.getTeamById(teamId);
142148

143149
if (!team) {
144-
return reply.status(404).send({
150+
const errorResponse = {
145151
success: false,
146-
error: 'Team not found',
147-
});
152+
error: 'Team not found'
153+
};
154+
const jsonString = JSON.stringify(errorResponse);
155+
return reply.status(404).type('application/json').send(jsonString);
148156
}
149157

150158
// Check if user has access to this team
151159
const isTeamMember = await TeamService.isTeamMember(teamId, request.user.id);
152160

153161
if (!isTeamMember) {
154-
return reply.status(403).send({
162+
const errorResponse = {
155163
success: false,
156-
error: 'You do not have access to this team',
157-
});
164+
error: 'You do not have access to this team'
165+
};
166+
const jsonString = JSON.stringify(errorResponse);
167+
return reply.status(403).type('application/json').send(jsonString);
158168
}
159169

160-
return reply.status(200).send({
170+
// Get user's role and permissions within this team
171+
const membership = await TeamService.getTeamMembership(teamId, request.user.id);
172+
const memberCount = await TeamService.getTeamMemberCount(teamId);
173+
174+
// Build team response with role information
175+
const teamWithRoleInfo = {
176+
...team,
177+
role: membership?.role || 'team_user',
178+
is_admin: membership?.role === 'team_admin',
179+
is_owner: team.owner_id === request.user.id,
180+
member_count: memberCount
181+
};
182+
183+
const successResponse = {
161184
success: true,
162-
data: team,
163-
});
185+
data: teamWithRoleInfo
186+
};
187+
const jsonString = JSON.stringify(successResponse);
188+
return reply.status(200).type('application/json').send(jsonString);
164189
} catch (error) {
165190
fastify.log.error(error, 'Error fetching team');
166-
return reply.status(500).send({
191+
const errorResponse = {
167192
success: false,
168-
error: 'Failed to fetch team',
169-
});
193+
error: 'Failed to fetch team'
194+
};
195+
const jsonString = JSON.stringify(errorResponse);
196+
return reply.status(500).type('application/json').send(jsonString);
170197
}
171198
});
172199

0 commit comments

Comments
 (0)