Skip to content

Commit 6843049

Browse files
authored
Accepting or rejecting mutations for user-teams (#204)
- Fixes search teams - Mutations to accept/reject teams - Exposes pronouns as ENUM
1 parent 6a520a0 commit 6843049

9 files changed

Lines changed: 163 additions & 47 deletions

File tree

src/authn/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
findUserByID,
99
updateUserProfileInfo,
1010
} from "~/datasources/queries/users";
11+
import { getUsername } from "~/datasources/queries/utils/createUsername";
1112
import { unauthorizedError } from "~/errors";
1213

1314
// Obtener el token de autorización de la solicitud, ya sea del encabezado de
@@ -129,7 +130,7 @@ export const upsertUserFromRequest = async ({
129130
imageUrl: avatar_url ? avatar_url : picture ? picture : "",
130131
externalId: sub,
131132
name,
132-
username: user_name,
133+
username: user_name ?? getUsername(),
133134
publicMetadata: payload,
134135
});
135136

src/datasources/db/teams.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,10 @@ export type TEAM = z.infer<typeof selectTeamsSchema>;
4646

4747
export const selectTeamsSchema = createSelectSchema(teamsSchema);
4848
export const insertTeamsSchema = createInsertSchema(teamsSchema);
49+
export const updateTeamsSchema = insertTeamsSchema
50+
.pick({
51+
name: true,
52+
description: true,
53+
teamStatus: true,
54+
})
55+
.partial();

src/datasources/db/userTeams.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,9 @@ export const userTeamsRelations = relations(userTeamsSchema, ({ one }) => ({
5656

5757
export const selectUserTeamsSchema = createSelectSchema(userTeamsSchema);
5858
export const insertUserTeamsSchema = createInsertSchema(userTeamsSchema);
59+
export const udpateUserTeamsSchema = insertUserTeamsSchema
60+
.pick({
61+
discipline: true,
62+
userParticipationStatus: true,
63+
})
64+
.partial();

src/datasources/db/users.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,14 @@ export type USER = z.infer<typeof selectUsersSchema>;
6363

6464
export const selectUsersSchema = createSelectSchema(usersSchema);
6565
export const insertUsersSchema = createInsertSchema(usersSchema);
66+
export const updateUsersSchema = insertUsersSchema
67+
.pick({
68+
name: true,
69+
lastName: true,
70+
bio: true,
71+
pronouns: true,
72+
gender: true,
73+
genderOtherText: true,
74+
username: true,
75+
})
76+
.partial();

src/schema/teams/mutations.ts

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
insertUserTeamsSchema,
88
selectTeamsSchema,
99
teamsSchema,
10+
udpateUserTeamsSchema,
11+
updateTeamsSchema,
1012
UserParticipationStatusEnum,
1113
UserTeamRoleEnum,
1214
userTeamsSchema,
@@ -42,7 +44,7 @@ builder.mutationField("createTeam", (t) =>
4244
}),
4345
},
4446
authz: {
45-
rules: ["IsAuthenticated"],
47+
rules: ["IsSuperAdmin"],
4648
},
4749
resolve: async (root, { input }, { DB, USER }) => {
4850
if (!USER) {
@@ -130,7 +132,7 @@ builder.mutationField("addPersonToTeam", (t) =>
130132
}),
131133
},
132134
authz: {
133-
rules: ["IsAuthenticated"],
135+
rules: ["IsSuperAdmin"],
134136
},
135137
resolve: async (root, { input }, { USER, DB, logger }) => {
136138
const { teamId, userEmail } = input;
@@ -227,7 +229,7 @@ builder.mutationField("deletePersonFomTeam", (t) =>
227229
}),
228230
},
229231
authz: {
230-
rules: ["IsAuthenticated"],
232+
rules: ["IsSuperAdmin"],
231233
},
232234
resolve: async (root, { input }, { USER, DB }) => {
233235
const { teamId, userId } = input;
@@ -257,7 +259,7 @@ builder.mutationField("deletePersonFomTeam", (t) =>
257259
}),
258260
);
259261

260-
const updateTeam = builder.inputType("updateTeam", {
262+
const updateTeam = builder.inputType("UpdateTeamInput", {
261263
fields: (t) => ({
262264
teamId: t.string({
263265
required: true,
@@ -273,7 +275,7 @@ const updateTeam = builder.inputType("updateTeam", {
273275

274276
builder.mutationField("updateTeam", (t) =>
275277
t.field({
276-
description: "Try to add a person to a team",
278+
description: "Updates a team information",
277279
type: TeamRef,
278280
args: {
279281
input: t.arg({
@@ -306,13 +308,14 @@ builder.mutationField("updateTeam", (t) =>
306308
addToObjectIfPropertyExists(properties, "name", name);
307309
addToObjectIfPropertyExists(properties, "description", description);
308310

309-
const teamToUpdate = insertTeamsSchema.parse(properties);
311+
const teamToUpdate = updateTeamsSchema.parse(properties);
310312

311-
await DB.update(teamsSchema)
313+
const udpatedTeam = await DB.update(teamsSchema)
312314
.set(teamToUpdate)
313-
.where(eq(teamsSchema.id, teamId));
315+
.where(eq(teamsSchema.id, teamId))
316+
.returning();
314317

315-
return team;
318+
return selectTeamsSchema.parse(udpatedTeam[0]);
316319
},
317320
}),
318321
);
@@ -330,7 +333,7 @@ const acceptTeamInvitationInput = builder.inputType(
330333

331334
builder.mutationField("acceptTeamInvitation", (t) =>
332335
t.field({
333-
description: "Accept an invitation to a team",
336+
description: "Accept the user's invitation to a team",
334337
type: TeamRef,
335338
args: {
336339
input: t.arg({
@@ -362,13 +365,71 @@ builder.mutationField("acceptTeamInvitation", (t) =>
362365
throw new GraphQLError("You do not have permission to edit this team");
363366
}
364367

365-
const teamToUpdate = insertTeamsSchema.parse({
368+
const teamToUpdate = udpateUserTeamsSchema.parse({
366369
userParticipationStatus: UserParticipationStatusEnum.accepted,
367370
});
368371

369372
await DB.update(userTeamsSchema)
370373
.set(teamToUpdate)
371-
.where(eq(userTeamsSchema.teamId, teamId));
374+
.where(eq(userTeamsSchema.id, teamAndUsers?.id));
375+
376+
return team;
377+
},
378+
}),
379+
);
380+
381+
const rejectTeamInvitationInput = builder.inputType(
382+
"RejectTeamInvitationInput",
383+
{
384+
fields: (t) => ({
385+
teamId: t.string({
386+
required: true,
387+
}),
388+
}),
389+
},
390+
);
391+
392+
builder.mutationField("rejectTeamInvitation", (t) =>
393+
t.field({
394+
description: "Reject the user's invitation to a team",
395+
type: TeamRef,
396+
args: {
397+
input: t.arg({
398+
type: rejectTeamInvitationInput,
399+
required: true,
400+
}),
401+
},
402+
authz: {
403+
rules: ["IsAuthenticated"],
404+
},
405+
resolve: async (root, { input }, { USER, DB }) => {
406+
const { teamId } = input;
407+
408+
if (!USER) {
409+
throw new GraphQLError("User not found");
410+
}
411+
412+
const teamAndUsers = await DB.query.userTeamsSchema.findFirst({
413+
where: (t, { eq, and }) =>
414+
and(eq(t.teamId, teamId), eq(t.userId, USER.id)),
415+
with: {
416+
team: true,
417+
user: true,
418+
},
419+
});
420+
const team = teamAndUsers?.team;
421+
422+
if (!team) {
423+
throw new GraphQLError("You do not have permission to edit this team");
424+
}
425+
426+
const teamToUpdate = udpateUserTeamsSchema.parse({
427+
userParticipationStatus: UserParticipationStatusEnum.not_accepted,
428+
});
429+
430+
await DB.update(userTeamsSchema)
431+
.set(teamToUpdate)
432+
.where(eq(userTeamsSchema.id, teamAndUsers?.id));
372433

373434
return team;
374435
},

src/schema/teams/tests/mutations.test.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919

2020
describe("Team", () => {
2121
describe("Should create a team", () => {
22-
it("As an admin", async () => {
22+
it("As an super admin", async () => {
2323
const user1 = await insertUser();
2424
const event = await insertEvent();
2525

@@ -28,22 +28,19 @@ describe("Team", () => {
2828
userId: user1.id,
2929
role: "admin",
3030
});
31-
const response = await executeGraphqlOperationAsUser<
31+
const response = await executeGraphqlOperationAsSuperAdmin<
3232
CreateTeamMutation,
3333
CreateTeamMutationVariables
34-
>(
35-
{
36-
document: CreateTeam,
37-
variables: {
38-
input: {
39-
description: faker.lorem.paragraph(3),
40-
name: faker.lorem.words(3),
41-
eventId: event.id,
42-
},
34+
>({
35+
document: CreateTeam,
36+
variables: {
37+
input: {
38+
description: faker.lorem.paragraph(3),
39+
name: faker.lorem.words(3),
40+
eventId: event.id,
4341
},
4442
},
45-
user1,
46-
);
43+
});
4744

4845
assert.equal(response.errors, undefined);
4946
const team = await findTeamById(response?.data?.createTeam?.id);
@@ -76,10 +73,12 @@ describe("Team", () => {
7673
});
7774
it("Should error on creating a second team", async () => {
7875
const event = await insertEvent();
79-
const user = await insertUser();
76+
const user = await insertUser({
77+
isSuperAdmin: true,
78+
});
8079

8180
// Create the first team
82-
await executeGraphqlOperationAsUser<
81+
await executeGraphqlOperationAsSuperAdmin<
8382
CreateTeamMutation,
8483
CreateTeamMutationVariables
8584
>(
@@ -97,7 +96,7 @@ describe("Team", () => {
9796
);
9897

9998
// Attempt to create a second team for the same event
100-
const response = await executeGraphqlOperationAsUser<
99+
const response = await executeGraphqlOperationAsSuperAdmin<
101100
CreateTeamMutation,
102101
CreateTeamMutationVariables
103102
>(

src/schema/user/mutations.ts

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { GraphQLError } from "graphql";
33

44
import { builder } from "~/builder";
55
import {
6+
PronounsEnum,
67
selectUsersSchema,
8+
updateUsersSchema,
79
usersSchema,
810
usersToCommunitiesSchema,
911
} from "~/datasources/db/schema";
1012
import { UserRef } from "~/schema/shared/refs";
13+
import { pronounsEnum } from "~/schema/user/types";
1114
import {
1215
UserRoleCommunity,
1316
canUpdateUserRoleInCommunity,
@@ -21,21 +24,12 @@ const userEditInput = builder.inputType("userEditInput", {
2124
lastName: t.string({ required: false }),
2225
bio: t.string({ required: false }),
2326
username: t.string({ required: false }),
27+
pronouns: t.field({ type: pronounsEnum, required: false }),
2428
}),
2529
});
26-
const updateUserRoleInCommunityInput = builder.inputType(
27-
"updateUserRoleInCommunityInput",
28-
{
29-
fields: (t) => ({
30-
userId: t.string({ required: true }),
31-
communityId: t.string({ required: true }),
32-
role: t.string({ required: true }),
33-
}),
34-
},
35-
);
3630

37-
builder.mutationFields((t) => ({
38-
updateUser: t.field({
31+
builder.mutationField("updateUser", (t) =>
32+
t.field({
3933
description: "Update a user",
4034
type: UserRef,
4135
nullable: false,
@@ -47,7 +41,7 @@ builder.mutationFields((t) => ({
4741
},
4842
resolve: async (root, { input }, ctx) => {
4943
try {
50-
const { id, name, lastName, bio, username } = input;
44+
const { id, name, lastName, bio, username, pronouns } = input;
5145

5246
if (!ctx.USER) {
5347
throw new Error("User not found");
@@ -62,6 +56,7 @@ builder.mutationFields((t) => ({
6256
lastName?: string;
6357
bio?: string;
6458
username?: string;
59+
pronouns?: PronounsEnum;
6560
};
6661

6762
if (name) {
@@ -80,9 +75,14 @@ builder.mutationFields((t) => ({
8075
updateFields.username = username;
8176
}
8277

78+
if (pronouns) {
79+
updateFields.pronouns = pronouns;
80+
}
81+
82+
const userData = updateUsersSchema.parse(updateFields);
8383
const user = (
8484
await ctx.DB.update(usersSchema)
85-
.set(updateFields)
85+
.set(userData)
8686
.where(eq(usersSchema.id, id))
8787
.returning()
8888
)?.[0];
@@ -95,7 +95,21 @@ builder.mutationFields((t) => ({
9595
}
9696
},
9797
}),
98-
updateUserRoleInCommunity: t.field({
98+
);
99+
100+
const updateUserRoleInCommunityInput = builder.inputType(
101+
"updateUserRoleInCommunityInput",
102+
{
103+
fields: (t) => ({
104+
userId: t.string({ required: true }),
105+
communityId: t.string({ required: true }),
106+
role: t.string({ required: true }),
107+
}),
108+
},
109+
);
110+
111+
builder.mutationField("updateUserRoleInCommunity", (t) =>
112+
t.field({
99113
description: "Update a user role",
100114
type: UserRef,
101115
nullable: false,
@@ -141,4 +155,4 @@ builder.mutationFields((t) => ({
141155
}
142156
},
143157
}),
144-
}));
158+
);

0 commit comments

Comments
 (0)