From 2c763aa03a482759a0956a1ab86ce3a56af2ab83 Mon Sep 17 00:00:00 2001 From: Ayoobf Date: Sun, 31 Aug 2025 01:00:26 -0400 Subject: [PATCH 1/3] del nvmrc --- .nvmrc | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 518633e..0000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -lts/fermium From 58f2669a70a92e353104c35cbb3b3095c6020cc4 Mon Sep 17 00:00:00 2001 From: Ayoobf Date: Mon, 15 Sep 2025 22:54:51 -0400 Subject: [PATCH 2/3] Added registration checks and udpated tests --- src/functions/teams/create/handler.ts | 34 ++++++++- tests/teams-create.test.ts | 101 +++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/src/functions/teams/create/handler.ts b/src/functions/teams/create/handler.ts index 27f2ff4..3bbe2e1 100644 --- a/src/functions/teams/create/handler.ts +++ b/src/functions/teams/create/handler.ts @@ -74,6 +74,18 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent = async (ev }; } + // Check if auth user has valid registration status for team creation + const validStatesForTeamCreation = ['registered', 'confirmation', 'coming']; + if (!validStatesForTeamCreation.includes(authUser.registration_status)) { + return { + statusCode: 400, + body: JSON.stringify({ + statusCode: 400, + message: `User must be in 'registered', 'confirmation', or 'coming' state to create a team. Current state: ${authUser.registration_status}`, + }), + }; + } + // Check if user already leads a team if (authUser.team_info?.role === 'leader') { return { @@ -112,11 +124,17 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent = async (ev const invalidEmails = []; const emailsAlreadyInTeams = []; + const emailsWithInvalidStatus = []; for (const email of memberEmails) { const user = await users.findOne({ email: email }); - if (!user) invalidEmails.push(email); - else if (user.confirmed_team === true) emailsAlreadyInTeams.push(email); + if (!user) + invalidEmails.push(email); + else if (user.confirmed_team === true) + emailsAlreadyInTeams.push(email); + else if (!validStatesForTeamCreation.includes(user.registration_status)) + emailsWithInvalidStatus.push({ email, status: user.registration_status }); + } // Return errors if any validation failed @@ -142,6 +160,18 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent = async (ev }; } + if (emailsWithInvalidStatus.length > 0) { + return { + statusCode: 400, + body: JSON.stringify({ + statusCode: 400, + message: 'Some users have invalid registration status for team creation', + invalid_status_users: emailsWithInvalidStatus, + required_status: validStatesForTeamCreation, + }), + }; + } + // Validate team size (leader + members <= 4) if (memberEmails.length > 3) { return { diff --git a/tests/teams-create.test.ts b/tests/teams-create.test.ts index 2196276..a55ac54 100644 --- a/tests/teams-create.test.ts +++ b/tests/teams-create.test.ts @@ -24,7 +24,7 @@ const mockTeamsCollection = { const mockDbInstance = { connect: jest.fn(), getClient: jest.fn(() => mockClient), - getCollection: jest.fn((name: string) => { + getCollection: jest.fn((name) => { if (name === 'users') return mockUsersCollection; if (name === 'teams') return mockTeamsCollection; return null; @@ -78,12 +78,14 @@ describe('Teams Create Handler', () => { email: 'leader@test.com', confirmed_team: false, team_info: null, + registration_status: 'registered', }; const mockMemberUser = { email: 'member1@test.com', confirmed_team: false, team_info: null, + registration_status: 'registered', }; it('should successfully create team and send invitations', async () => { @@ -381,4 +383,101 @@ describe('Teams Create Handler', () => { expect.objectContaining({ session: mockSession }) ); }); + + it('should return 400 when leader has unregistered status', async () => { + const unregisteredLeader = { + ...mockLeaderUser, + registration_status: 'unregistered', + }; + mockUsersCollection.findOne.mockResolvedValue(unregisteredLeader); + + const mockEvent = createEvent(mockEventData, '/teams/create', 'POST'); + const result = await main(mockEvent, mockContext); + + expect(result.statusCode).toBe(400); + const body = JSON.parse(result.body); + expect(body.message).toBe( + "User must be in 'registered', 'confirmation', or 'coming' state to create a team. Current state: unregistered" + ); + }); + + it('should return 400 when leader has rejected status', async () => { + const rejectedLeader = { + ...mockLeaderUser, + registration_status: 'rejected', + }; + mockUsersCollection.findOne.mockResolvedValue(rejectedLeader); + + const mockEvent = createEvent(mockEventData, '/teams/create', 'POST'); + const result = await main(mockEvent, mockContext); + + expect(result.statusCode).toBe(400); + const body = JSON.parse(result.body); + expect(body.message).toBe( + "User must be in 'registered', 'confirmation', or 'coming' state to create a team. Current state: rejected" + ); + }); + + it('should return 400 when some members have invalid registration status', async () => { + const unregisteredMember = { + ...mockMemberUser, + email: 'member1@test.com', + registration_status: 'unregistered', + }; + + const waitlistMember = { + ...mockMemberUser, + email: 'member2@test.com', + registration_status: 'waitlist', + }; + + mockUsersCollection.findOne + .mockResolvedValueOnce(mockLeaderUser) // Auth user lookup + .mockResolvedValueOnce(unregisteredMember) // member1@test.com lookup + .mockResolvedValueOnce(waitlistMember); // member2@test.com lookup + + const mockEvent = createEvent(mockEventData, '/teams/create', 'POST'); + const result = await main(mockEvent, mockContext); + + expect(result.statusCode).toBe(400); + const body = JSON.parse(result.body); + expect(body.message).toBe('Some users have invalid registration status for team creation'); + expect(body.invalid_status_users).toEqual([ + { email: 'member1@test.com', status: 'unregistered' }, + { email: 'member2@test.com', status: 'waitlist' }, + ]); + expect(body.required_status).toEqual(['registered', 'confirmation', 'coming']); + }); + + it('should successfully create team when all users have valid registration statuses', async () => { + const confirmationLeader = { + ...mockLeaderUser, + registration_status: 'confirmation', + }; + + const comingMember = { + ...mockMemberUser, + email: 'member1@test.com', + registration_status: 'coming', + }; + + const registeredMember = { + ...mockMemberUser, + email: 'member2@test.com', + registration_status: 'registered', + }; + + mockUsersCollection.findOne + .mockResolvedValueOnce(confirmationLeader) // Auth user lookup + .mockResolvedValueOnce(comingMember) // member1@test.com lookup + .mockResolvedValueOnce(registeredMember); // member2@test.com lookup + + const mockEvent = createEvent(mockEventData, '/teams/create', 'POST'); + const result = await main(mockEvent, mockContext); + + expect(result.statusCode).toBe(200); + const body = JSON.parse(result.body); + expect(body.message).toBe('Team created successfully'); + expect(body.team_id).toBeDefined(); + }); }); From 4eabe9185744b0668acff35cfa3c15e7c84eea1e Mon Sep 17 00:00:00 2001 From: Ayoobf Date: Mon, 15 Sep 2025 23:04:07 -0400 Subject: [PATCH 3/3] prettier --- src/functions/teams/create/handler.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/functions/teams/create/handler.ts b/src/functions/teams/create/handler.ts index 3bbe2e1..974e972 100644 --- a/src/functions/teams/create/handler.ts +++ b/src/functions/teams/create/handler.ts @@ -128,13 +128,10 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent = async (ev for (const email of memberEmails) { const user = await users.findOne({ email: email }); - if (!user) - invalidEmails.push(email); - else if (user.confirmed_team === true) - emailsAlreadyInTeams.push(email); - else if (!validStatesForTeamCreation.includes(user.registration_status)) + if (!user) invalidEmails.push(email); + else if (user.confirmed_team === true) emailsAlreadyInTeams.push(email); + else if (!validStatesForTeamCreation.includes(user.registration_status)) emailsWithInvalidStatus.push({ email, status: user.registration_status }); - } // Return errors if any validation failed