Skip to content

Commit 1c000d3

Browse files
Account Management API: Added v2 API endpoint to remove collaborators from a project via /api/v2/projects/collaborators/remove.
1 parent c797ac6 commit 1c000d3

File tree

5 files changed

+105
-4
lines changed

5 files changed

+105
-4
lines changed

src/packages/next/lib/api/schema/projects/collaborators/remove.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import { z } from "../../../framework";
33
import { FailedAPIOperationSchema, OkAPIOperationSchema } from "../../common";
44

55
import { ProjectIdSchema } from "../common";
6+
import { AccountIdSchema } from "../../accounts/common";
67

78
// OpenAPI spec
89
//
910
export const RemoveProjectCollaboratorInputSchema = z
1011
.object({
1112
project_id: ProjectIdSchema,
13+
account_id: AccountIdSchema,
1214
})
13-
.describe("Remove a collaborator from a project.");
15+
.describe("Remove a collaborator from an existing project.");
1416

1517
export const RemoveProjectCollaboratorOutputSchema = z.union([
1618
FailedAPIOperationSchema,

src/packages/next/pages/api/v2/projects/collaborators/add.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ async function handle(req, res) {
4040
}
4141

4242
export default apiRoute({
43-
add: apiRouteOperation({
43+
addProjectCollaborator: apiRouteOperation({
4444
method: "POST",
4545
openApiOperation: {
46-
tags: ["Projects", "Administrators"],
46+
tags: ["Projects", "Admin"],
4747
},
4848
})
4949
.input({
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
API endpoint to remove a user from an existing project.
3+
4+
Permissions checks are performed by the underlying API call and are NOT
5+
executed at this stage.
6+
7+
*/
8+
import { db } from "@cocalc/database";
9+
import { remove_collaborators_from_projects } from "@cocalc/server/projects/collab";
10+
11+
import getAccountId from "lib/account/get-account";
12+
import getParams from "lib/api/get-params";
13+
import { apiRoute, apiRouteOperation } from "lib/api";
14+
import { OkStatus } from "lib/api/status";
15+
import {
16+
RemoveProjectCollaboratorInputSchema,
17+
RemoveProjectCollaboratorOutputSchema,
18+
} from "lib/api/schema/projects/collaborators/remove";
19+
20+
async function handle(req, res) {
21+
const { project_id, account_id } = getParams(req);
22+
const client_account_id = await getAccountId(req);
23+
24+
try {
25+
if (!client_account_id) {
26+
throw Error("must be signed in");
27+
}
28+
29+
await remove_collaborators_from_projects(
30+
db(),
31+
client_account_id,
32+
[account_id],
33+
[project_id],
34+
);
35+
36+
res.json(OkStatus);
37+
} catch (err) {
38+
res.json({ error: err.message });
39+
}
40+
}
41+
42+
export default apiRoute({
43+
removeProjectCollaborator: apiRouteOperation({
44+
method: "POST",
45+
openApiOperation: {
46+
tags: ["Projects", "Admin"],
47+
},
48+
})
49+
.input({
50+
contentType: "application/json",
51+
body: RemoveProjectCollaboratorInputSchema,
52+
})
53+
.outputs([
54+
{
55+
status: 200,
56+
contentType: "application/json",
57+
body: RemoveProjectCollaboratorOutputSchema,
58+
},
59+
])
60+
.handler(handle),
61+
});

src/packages/next/pages/api/v2/shopping/cart/add.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async function add(req): Promise<number | undefined> {
5252
}
5353

5454
export default apiRoute({
55-
add: apiRouteOperation({
55+
addCartItem: apiRouteOperation({
5656
method: "POST",
5757
openApiOperation: {
5858
tags: ["Shopping"],

src/packages/server/projects/collab.ts

+38
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,44 @@ export async function add_collaborators_to_projects(
6767
}
6868
}
6969

70+
export async function remove_collaborators_from_projects(
71+
db: PostgreSQL,
72+
account_id: string,
73+
accounts: string[],
74+
projects: string[], // can be empty strings if tokens specified (since they determine project_id)
75+
): Promise<void> {
76+
try {
77+
// Ensure user is allowed to modify project(s)
78+
//
79+
await verify_write_access_to_projects(db, account_id, projects);
80+
} catch (err) {
81+
// Users can always remove themselves from a project.
82+
//
83+
if (accounts.length == 1 && account_id == accounts[0]) {
84+
await verify_course_access_to_project(db, account_id, projects[0]);
85+
} else {
86+
throw err;
87+
}
88+
}
89+
90+
/* Right now this function is called from outside typescript
91+
(e.g., api from user), so we have to do extra type checking.
92+
Also, the input is uuid's, which typescript can't check. */
93+
verify_types(account_id, accounts, projects);
94+
95+
// Remove users from projects
96+
//
97+
for (const i in projects) {
98+
const project_id: string = projects[i];
99+
const account_id: string = accounts[i];
100+
101+
await callback2(db.remove_user_from_project, {
102+
project_id,
103+
account_id,
104+
});
105+
}
106+
}
107+
70108
// This is only meant to be used here in support of
71109
// add_collaborators_to_projects -- do not export it.
72110
async function verify_write_access_to_projects(

0 commit comments

Comments
 (0)