1import { Inject, Body, Controller, Delete, Get, Param, Patch, Post, Query, Req } from "@nestjs/common";
2import type { Request } from "express";
3import { z } from "zod";
4import { WorkspacesService } from "./workspaces.service.js";
5import { DatabaseService } from "../databases/database.service.js";
6import { ZodValidate } from "../../common/pipes/zod-validation.pipe.js";
7import { requireActor, requireUser } from "../../common/types.js";
8import { ApiError } from "../../common/errors.js";
9import {
10 CreateWorkspaceDto,
11 type CreateWorkspaceInput,
12 InviteMemberDto,
13 type InviteMemberInput,
14 ListMembersQuery,
15 type ListMembersInput,
16 ListWorkspacesQuery,
17 type ListWorkspacesInput,
18 TransferWorkspaceDto,
19 type TransferWorkspaceInput,
20 UpdateMemberRoleDto,
21 type UpdateMemberRoleInput,
22 UpdateWorkspaceDto,
23 type UpdateWorkspaceInput
24} from "./dto.js";
25
26const DatabasesListQuery = z.object({
27 limit: z.coerce.number().int().min(1).max(100).optional()
28});
29
30@Controller("workspaces")
31export class WorkspacesController {
32 constructor(
33 @Inject(WorkspacesService) private readonly workspaces: WorkspacesService,
34 @Inject(DatabaseService) private readonly databases: DatabaseService
35 ) {}
36
37
38 @Get()
39 list(
40 @Query(ZodValidate(ListWorkspacesQuery)) query: ListWorkspacesInput,
41 @Req() req: Request
42 ) {
43 return this.workspaces.listMine(requireUser(req), query);
44 }
45
46 @Post()
47 create(
48 @Body(ZodValidate(CreateWorkspaceDto)) body: CreateWorkspaceInput,
49 @Req() req: Request
50 ) {
51 return this.workspaces.create(requireUser(req), body);
52 }
53
54
55
56
57
58 @Get(":id")
59 get(@Param("id") id: string, @Req() req: Request) {
60 return this.workspaces.get(id, requireActor(req));
61 }
62
63 @Patch(":id")
64 update(
65 @Param("id") id: string,
66 @Body(ZodValidate(UpdateWorkspaceDto)) body: UpdateWorkspaceInput,
67 @Req() req: Request
68 ) {
69 return this.workspaces.update(id, requireActor(req), body, req);
70 }
71
72 @Delete(":id")
73 remove(@Param("id") id: string, @Req() req: Request) {
74 return this.workspaces.remove(id, requireUser(req), req).then(() => ({ deleted: true }));
75 }
76
77
78
79 @Get(":id/members")
80 listMembers(
81 @Param("id") id: string,
82 @Query(ZodValidate(ListMembersQuery)) query: ListMembersInput,
83 @Req() req: Request
84 ) {
85 return this.workspaces.listMembers(id, requireActor(req), query);
86 }
87
88 @Post(":id/members/invites")
89 invite(
90 @Param("id") id: string,
91 @Body(ZodValidate(InviteMemberDto)) body: InviteMemberInput,
92 @Req() req: Request
93 ) {
94 return this.workspaces.invite(id, requireUser(req), body, req);
95 }
96
97 @Post(":id/members/invites/:inviteId/accept")
98 acceptInvite(
99 @Param("id") id: string,
100 @Param("inviteId") _inviteId: string,
101 @Query("token") token: string | undefined,
102 @Req() req: Request
103 ) {
104 if (!token) {
105 throw ApiError.validation("Invitation token required (?token=…).", [{ field: "token", issue: "required" }]);
106 }
107 return this.workspaces.acceptInvite(id, requireUser(req), token, req);
108 }
109
110 @Patch(":id/members/:userId")
111 updateMemberRole(
112 @Param("id") id: string,
113 @Param("userId") userId: string,
114 @Body(ZodValidate(UpdateMemberRoleDto)) body: UpdateMemberRoleInput,
115 @Req() req: Request
116 ) {
117 return this.workspaces.updateMemberRole(id, requireUser(req), userId, body.role, req);
118 }
119
120 @Delete(":id/members/:userId")
121 removeMember(
122 @Param("id") id: string,
123 @Param("userId") userId: string,
124 @Req() req: Request
125 ) {
126 return this.workspaces.removeMember(id, requireUser(req), userId, req).then(() => ({ removed: true }));
127 }
128
129
130
131 @Get(":id/databases")
132 listDatabases(
133 @Param("id") id: string,
134 @Query(ZodValidate(DatabasesListQuery)) query: z.infer<typeof DatabasesListQuery>,
135 @Req() req: Request
136 ) {
137 return this.databases.listByWorkspace(id, requireActor(req), query.limit ?? 50);
138 }
139
140 @Get(":id/usage")
141 usage(@Param("id") id: string, @Req() req: Request) {
142 return this.workspaces.usage(id, requireActor(req));
143 }
144
145 @Post(":id/transfer")
146 transfer(
147 @Param("id") id: string,
148 @Body(ZodValidate(TransferWorkspaceDto)) body: TransferWorkspaceInput,
149 @Req() req: Request
150 ) {
151 return this.workspaces.transfer(id, requireUser(req), body.newOwnerId, req);
152 }
153
154
155
156 @Post(":id/archive")
157 archive(@Param("id") id: string, @Req() req: Request) {
158 return this.workspaces.archive(id, requireUser(req), req);
159 }
160
161 @Post(":id/archive/restore")
162 restore(@Param("id") id: string, @Req() req: Request) {
163 return this.workspaces.restoreWorkspace(id, requireUser(req), req);
164 }
165
166 @Get(":id/stats")
167 stats(@Param("id") id: string, @Req() req: Request) {
168 return this.workspaces.stats(id, requireUser(req));
169 }
170
171
172
173 @Get(":id/activity")
174 activity(
175 @Param("id") id: string,
176 @Query("cursor") cursor: string | undefined,
177 @Query("limit") limit: string | undefined,
178 @Req() req: Request
179 ) {
180 return this.workspaces.activity(id, requireActor(req), { cursor, limit });
181 }
182}
183