From eca4f1b56c1d71d381a287e9558cd28167e39ca3 Mon Sep 17 00:00:00 2001 From: TomatoCake <60300461+DEVTomatoCake@users.noreply.github.com> Date: Sat, 24 Aug 2024 07:37:34 +0200 Subject: [PATCH] Listing & creation of Developer Portal teams --- assets/openapi.json | Bin 610464 -> 613045 bytes assets/schemas.json | Bin 21759522 -> 22134205 bytes src/api/routes/teams.ts | 84 ++++++++++++++++-- src/util/entities/TeamMember.ts | 8 ++ .../mariadb/1724477620293-teamMemberRole.ts | 17 ++++ .../mysql/1724477620293-teamMemberRole.ts | 17 ++++ .../postgres/1724477620293-teamMemberRole.ts | 15 ++++ src/util/schemas/ApplicationCreateSchema.ts | 8 +- src/util/schemas/TeamCreateSchema.ts | 21 +++++ src/util/schemas/index.ts | 1 + .../schemas/responses/TeamListResponse.ts | 21 +++++ src/util/schemas/responses/index.ts | 7 +- 12 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 src/util/migration/mariadb/1724477620293-teamMemberRole.ts create mode 100644 src/util/migration/mysql/1724477620293-teamMemberRole.ts create mode 100644 src/util/migration/postgres/1724477620293-teamMemberRole.ts create mode 100644 src/util/schemas/TeamCreateSchema.ts create mode 100644 src/util/schemas/responses/TeamListResponse.ts diff --git a/assets/openapi.json b/assets/openapi.json index 14d13fa44732ad06f5b834f6dd7938d3d1a44e18..5a973072604dc48ba8cb8e277987d685f0a47095 100644 GIT binary patch delta 479 zcmXYrOK1~O7=`&~=FUv(BN+(9L@2kW4<%G11w}1l6>~q zxgv54!}vL??80QWYtKA2LTZ48BA!rir=py~;2CryJuap3%oQnxr&mD}Ut)bCH+U@k zx&p(}UsMD)lObJ&lYk$Vp&o@+f{^nkithtp$nhduuuHfi0nF+ zc(9zn%{oblR%X9A>>G{38ia*4>3vgTHWr^qFGPOtIL_PxBHU3!`KxhtA7C zUa8EUsCpc?U&^Bz&Fge!Y+zI&m%Ahu>FVO0-i)8W~W+3=ruKwzkPH(h;%u zleUQWN61*B>XaF}>NTX?*)y+Kn^c$RxHW$hk(OL{Xz?;l`Z4_3;nQldcp1 delta 160 zcmV;R0AK&LwI!gTC9n_>m;Sp09+yt<0|=K3*8(1w-k<>nmp;(~9G7su174HRm^7Ck zF9ZvhEHw!Ymu;v5Ta(aHWs_j6UW4Bex8D%~PL{W*r~#D%w^^$JIRS@ltpT@ftpd%P zm;Xxx2DffX1NgXyW&{MMW&{O$mvCtXh?j8o1s<2pf(0g*fb|3xm%fb!8HY881&1|< O28T6=2e&nc2!PX8&_D$M diff --git a/assets/schemas.json b/assets/schemas.json index b911257201a0e35434a13785f7ab9cc7074807f7..08ba372c4e19ee04607e4b8e375834c88cf9cc9d 100644 GIT binary patch delta 16566 zcmc(m`&U%g701_sfqB5d9ULAr0|Uq-3L->Md;~?o7YbE;pb5_aiiqGFL`7bD0%|Tg zfrE%MfLKMNlGw0mN^;Sz*xEKLkhC?ZMF_3RxT>?n`l7|&k*=ow2X=m#UuI^_XTJOF zefHUVpWAYzUGc@}bwzuug0-)i;L5nFj3jnfrq>$g$(L0mJ3z7nnS74*#C&PT)>xEk zRvI%`&bSv{KCHP}qc!==oJKq$Oyl*bjrB`9C~4zn6ULp;Dp*<0N-YZ;cJ#8Fn31(* z6Z_;Z_8MlQd2$w>B-PqyWTh44=do=ewrUnuQ$G*Fju#}DS-iKMl%;gZCeS<0HgKoe zHiAdQQxOmG-u8v4P;yENN=gTbT)ZVQ0nckO`e(vp5=itW)2NrO| zk+4TWWD1KmF3~feydf1!dnY2q`U9rR(Hu!&mnO;l-u#}WqF7;yj^&7%TB>}&Qsp}Z z)62)#UbF+GO8x0E#I>grX#h;5ff=VUq1_&npxa~eQA{tV)hr0AS#TGsc`MvQpu&CX zX-sdTnYE#iSsV5~s(EeH)4)a@9*e59;#dS!9Gf1FxoOc6Wh9I!XYMg#hD=+-ENE+( zoqZG&y3FkzSmqWLhN`r)WiE8K%tKASbhY<Tk3*Z6GR%~m9)%l8I-v#--9YwBtxVjAsZFi=ez>?oL8>Lv@tEHNrZx$ zRYRz8!#k}3-f8V1s(CLSPJ)Yv*Bz-x+<+ykvop3Z=UNr5?aoi412R1f$h?Cva{%M` zWEm}Sc^67t-dlreaghuhpOS(KJ@1eP=N;0OsL-c01D?|NTTr3jNwVNON%j%E&`mVc zrt%HYRKC#(PpJrfJeC8G$2R2|&_Y*)HkNLN#?riXc;!Z-*;LvZNF)bm<$pG-K!#&t zDz;d~*H*FBx^1)=)4+M7+aYgsNAXECXo8vg9oz+e2X}km76PwYVoykK;8Z)QrO^>AjY<`2 z#_gzc4yHYla_Es%TtRiT?y^egE<32fgfbB-qx!K!pdX`Im}DvxSAkGmU4#i`B2-HE zK0ge5pC1{+^mE!#@*#AT@Ov@k()`gH$R9lxj+cAIUAljt0s8lSMDUI_;*?QTDx?0d zYR~$=s>3v~p^#J4UAyaH*X|Rju1teQ8X#!o@@=ZH-8s3(K z89tW1CEc2_b7%JUd^YH%)X68Nz84lUD<#;U^;T=#7H6CpiTN>B@G zdMNW7IF#8_gSsrMe&~f&KYZJVTKH_r`Xg-0`corjzoIUs&yHOqm&$jvt5-kH`Zt zQi5t}{*oXg!X-gYj-nd5XpRFBism>H)CgkYkwVVLgOUjG;6z?w)`)y%Bu9kGNEK

>2h2)6?R zNETl6Fwx9gZ}$kLt#6TU@rudyX1>99G7%blgUH!aXqiw{TP{w4gz}412;##~BKCgp zR3h9D4kgR*)>a&USZ_h_g>7L(C~SM1q~k5H$QG|8C|Od4*N+_>ennt75mp37kT}eL z!ryF}PK28+Ge`ZTgu+*ruOFx=_{To}5jD+>>+222`xlBZ>%0kGZ53-NV@> zSH+KBW}WY{eBFHOeX9^tfi{XrS(9D)G*+6~&oPtH#+~`hxa-G4haL5-$;rmm`Vb(W z&gO|tWEM?MpjvH)dI1q;sAEVBDz>90mIxg+3yBLV)=s&Y2zJUP1nC;-_)SMXu4*X} R;;Q0E6Q0_|W*f!+e*=Cgy+i;2 delta 4168 zcmaJ^Ygp4&7=I25V*?ZfZ;sq+hw1m8rn*9^L*xvPFU-rA4_q>(}~CqKvi%2 zQ9G#8ZjK`0YLcmjbW&dty{xx`%ldIj&IUd(#U2KxI20l{y;UuOTh)&BrPf-S6Ci<{ z0H-ZGtT85FBFfb`16Sh`j~I^H#k^1>2nMdOFcj=_1uCO)3A!k z5LV&!5~fr6`hd#UHy6QJWAjJ$G`rjnvdbR`DnqVxk1*5QA7*+7RM>P_yDJdZ?wZoG z)0V?k->GobH;8VxCeXl&UVH*fL-eG4 zHk_1)=#fmZ9!;kMb*~Er_d5B~`)o&>XOtk7KLS$uqj8u+|EvfRmDGlTq&9pOk`gKq zpnq26hRXkjrW&Gm>!aXqef08e))>2I>>e2l?vZn4n0U|>2ZN@0SS9JD1@qz3f_McI zG3{+y0KH8M*I>b3Q6$0@g)$$*?ie3~JI16*NUu{+qyQ)uy@}|UfVt3NV=4?ART_jq zhhx)WI9B}xW;|ldfDz;30qi2haam9t_xO3tQ*?X@h>mNvmRo0*{?@bGM>t#SAabF z`3Z=6j4=cSFa#@C>Z~s{#;}Wd0qkO4)F6{J#&BpT1c!#z&bCf*qNb=dV2WC+N5)~y z!@YhTxYxhD@dN8PXn4YU2v6AHjrh}RO&j4_Q&ApP=y3_J!MKFtPUKX&-n0qUn@Y|j z#biH)$U|63fFwc};3j72)%G5`5_^9Zs24pheB)0W_c}x4UKclH#AsK?>(JHlMn4v7 zW-^7$gS>*O3WY9;plPaIkfvh$ZTi%FRSq>@?H-R1baGb@_H^Dgf88?I z5Y|68R>?|Q;w1F%MJ>pu0hWu@rrcPIP*z5vHf|g~+X`KmbMG ziDaa(Y}JxBM;g8OBt$Q6POwP`HJc#R+_LLE>zq=-0ah*fvf66gg@t|8(hf&09WNmz zrozI89!=NtRytvuUO3$i7f$#1BG;uceSHwqcd882t;w{&n#|MRB9le`uzU-DSiY;k zT0b)D2Z+o%vl%;2+uIM?-m?=i%v*gPyww*jV%UN10XWb-_|!fmXNG5f0>d*uYp_@h z=PrWb+%LgcC5!SeK~es%Wti^p;AJ>Gc%>Y}Mzp`fi1sQ&u(3rj=j<@dIXm(qa;k2V z*okWLu7M`+dM@HXa|dof?!e8J2zF0fyzDP1UUusV1gD$M+=fkO?(D{}#_YSt8nX$9 zVB8H0A^Z)C9oded@~rWMmuK1I=nAs~;a8YNq!QECrilq(n zgx6|($h+9#J5Tu%e&;DaG;FRjLrVD041c1-w2nOigm>%-#M7lpeUR{~)TyKZ8Awjs z86-s28BDMObNb|m2(M3`PKvN|O|3G*n_6d(<;d^SXxnn%B+erIH;J=}85u$D-`5zQ zZVDxb_E-<$n1dnXVZs|S9wFG@q%lshu!Hzwa~MfMBH>o6=Ma9iI)Xfh#K44CgbP>N z9ZC4o?kKVWp>VaSF+#_s#*!Q?4M*DN68=bg9BII`-bo6=dne5&c^EpaHJ~ diff --git a/src/api/routes/teams.ts b/src/api/routes/teams.ts index 26570165..1328f661 100644 --- a/src/api/routes/teams.ts +++ b/src/api/routes/teams.ts @@ -1,29 +1,99 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import { Request, Response, Router } from "express"; import { route } from "@spacebar/api"; +import { + Team, + TeamCreateSchema, + TeamMember, + TeamMemberRole, + TeamMemberState, + User, +} from "@spacebar/util"; +import { HTTPError } from "lambert-server"; const router: Router = Router(); -router.get("/", route({}), async (req: Request, res: Response) => { - //TODO - res.send([]); -}); +router.get( + "/", + route({ + query: { + include_payout_account_status: { + type: "boolean", + description: + "Whether to include team payout account status in the response (default false)", + }, + }, + responses: { + 200: { + body: "TeamListResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const teams = await Team.find({ + where: { + owner_user_id: req.user_id, + }, + relations: ["members"], + }); + + res.send(teams); + }, +); + +router.post( + "/", + route({ + requestBody: "TeamCreateSchema", + responses: { + 200: { + body: "Team", + }, + }, + }), + async (req: Request, res: Response) => { + const user = await User.findOneOrFail({ + where: [{ id: req.user_id }], + select: ["mfa_enabled"], + }); + if (!user.mfa_enabled) + throw new HTTPError("You must enable MFA to create a team"); + + const body = req.body as TeamCreateSchema; + + const team = Team.create({ + name: body.name, + owner_user_id: req.user_id, + }); + await team.save(); + + await TeamMember.create({ + user_id: req.user_id, + team_id: team.id, + membership_state: TeamMemberState.ACCEPTED, + permissions: ["*"], + role: TeamMemberRole.ADMIN, + }).save(); + + res.json(team); + }, +); export default router; diff --git a/src/util/entities/TeamMember.ts b/src/util/entities/TeamMember.ts index 2cd04710..e4c18b89 100644 --- a/src/util/entities/TeamMember.ts +++ b/src/util/entities/TeamMember.ts @@ -25,6 +25,11 @@ export enum TeamMemberState { INVITED = 1, ACCEPTED = 2, } +export enum TeamMemberRole { + ADMIN = "admin", + DEVELOPER = "developer", + READ_ONLY = "read_only", +} @Entity({ name: "team_members", @@ -37,6 +42,9 @@ export class TeamMember extends BaseClass { @Column({ type: "simple-array" }) permissions: string[]; + @Column() + role: TeamMemberRole; + @Column({ nullable: true }) @RelationId((member: TeamMember) => member.team) team_id: string; diff --git a/src/util/migration/mariadb/1724477620293-teamMemberRole.ts b/src/util/migration/mariadb/1724477620293-teamMemberRole.ts new file mode 100644 index 00000000..ff4be7bf --- /dev/null +++ b/src/util/migration/mariadb/1724477620293-teamMemberRole.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class TeamMemberRole1724477620293 implements MigrationInterface { + name = "TeamMemberRole1724477620293"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `team_members` ADD COLUMN `role` VARCHAR(255) NOT NULL AFTER `permissions`", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `team_members` DROP COLUMN `role`", + ); + } +} diff --git a/src/util/migration/mysql/1724477620293-teamMemberRole.ts b/src/util/migration/mysql/1724477620293-teamMemberRole.ts new file mode 100644 index 00000000..ff4be7bf --- /dev/null +++ b/src/util/migration/mysql/1724477620293-teamMemberRole.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class TeamMemberRole1724477620293 implements MigrationInterface { + name = "TeamMemberRole1724477620293"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `team_members` ADD COLUMN `role` VARCHAR(255) NOT NULL AFTER `permissions`", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE `team_members` DROP COLUMN `role`", + ); + } +} diff --git a/src/util/migration/postgres/1724477620293-teamMemberRole.ts b/src/util/migration/postgres/1724477620293-teamMemberRole.ts new file mode 100644 index 00000000..d3276d91 --- /dev/null +++ b/src/util/migration/postgres/1724477620293-teamMemberRole.ts @@ -0,0 +1,15 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class TeamMemberRole1724477620293 implements MigrationInterface { + name = "TeamMemberRole1724477620293"; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + "ALTER TABLE team_members ADD COLUMN role text NOT NULL", + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query("ALTER TABLE team_members DROP COLUMN role"); + } +} diff --git a/src/util/schemas/ApplicationCreateSchema.ts b/src/util/schemas/ApplicationCreateSchema.ts index 17bbc94c..80956ec4 100644 --- a/src/util/schemas/ApplicationCreateSchema.ts +++ b/src/util/schemas/ApplicationCreateSchema.ts @@ -1,22 +1,22 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ export interface ApplicationCreateSchema { name: string; - team_id?: string | number; + team_id?: string; } diff --git a/src/util/schemas/TeamCreateSchema.ts b/src/util/schemas/TeamCreateSchema.ts new file mode 100644 index 00000000..5903a536 --- /dev/null +++ b/src/util/schemas/TeamCreateSchema.ts @@ -0,0 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +export interface TeamCreateSchema { + name: string; +} diff --git a/src/util/schemas/index.ts b/src/util/schemas/index.ts index 62199dfb..7d8abaa0 100644 --- a/src/util/schemas/index.ts +++ b/src/util/schemas/index.ts @@ -62,6 +62,7 @@ export * from "./RequestGuildMembersSchema"; export * from "./RoleModifySchema"; export * from "./RolePositionUpdateSchema"; export * from "./SelectProtocolSchema"; +export * from "./TeamCreateSchema"; export * from "./TemplateCreateSchema"; export * from "./TemplateModifySchema"; export * from "./TotpDisableSchema"; diff --git a/src/util/schemas/responses/TeamListResponse.ts b/src/util/schemas/responses/TeamListResponse.ts new file mode 100644 index 00000000..375f0ae6 --- /dev/null +++ b/src/util/schemas/responses/TeamListResponse.ts @@ -0,0 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import { Team } from "@spacebar/util"; + +export interface TeamListResponse extends Array {} diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts index accb26f5..070a2e55 100644 --- a/src/util/schemas/responses/index.ts +++ b/src/util/schemas/responses/index.ts @@ -1,17 +1,17 @@ /* Spacebar: A FOSS re-implementation and extension of the Discord.com backend. Copyright (C) 2023 Spacebar and Spacebar Contributors - + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ @@ -40,6 +40,7 @@ export * from "./InstanceStatsResponse"; export * from "./LocationMetadataResponse"; export * from "./MemberJoinGuildResponse"; export * from "./OAuthAuthorizeResponse"; +export * from "./TeamListResponse"; export * from "./Tenor"; export * from "./TokenResponse"; export * from "./TypedResponses";