Skip to content
Merged

Dev #143

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

27 changes: 27 additions & 0 deletions src/functions/teams/create/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent<typeof schema> = 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 {
Expand Down Expand Up @@ -112,11 +124,14 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent<typeof schema> = 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);
else if (!validStatesForTeamCreation.includes(user.registration_status))
emailsWithInvalidStatus.push({ email, status: user.registration_status });
}

// Return errors if any validation failed
Expand All @@ -142,6 +157,18 @@ const teamsCreate: ValidatedEventAPIGatewayProxyEvent<typeof schema> = 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 {
Expand Down
101 changes: 100 additions & 1 deletion tests/teams-create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -78,12 +78,14 @@ describe('Teams Create Handler', () => {
email: '[email protected]',
confirmed_team: false,
team_info: null,
registration_status: 'registered',
};

const mockMemberUser = {
email: '[email protected]',
confirmed_team: false,
team_info: null,
registration_status: 'registered',
};

it('should successfully create team and send invitations', async () => {
Expand Down Expand Up @@ -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: '[email protected]',
registration_status: 'unregistered',
};

const waitlistMember = {
...mockMemberUser,
email: '[email protected]',
registration_status: 'waitlist',
};

mockUsersCollection.findOne
.mockResolvedValueOnce(mockLeaderUser) // Auth user lookup
.mockResolvedValueOnce(unregisteredMember) // [email protected] lookup
.mockResolvedValueOnce(waitlistMember); // [email protected] 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: '[email protected]', status: 'unregistered' },
{ email: '[email protected]', 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: '[email protected]',
registration_status: 'coming',
};

const registeredMember = {
...mockMemberUser,
email: '[email protected]',
registration_status: 'registered',
};

mockUsersCollection.findOne
.mockResolvedValueOnce(confirmationLeader) // Auth user lookup
.mockResolvedValueOnce(comingMember) // [email protected] lookup
.mockResolvedValueOnce(registeredMember); // [email protected] 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();
});
});