Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check in later #82

Merged
merged 5 commits into from
Oct 24, 2024
Merged
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
10 changes: 10 additions & 0 deletions src/functions/attend-event/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ const attendEvent: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (ev
};
}

if (attendEvent.registration_status != 'checked_in') {
return {
statusCode: 409,
body: JSON.stringify({
statusCode: 409,
message: 'User has not checked in. Current status is ' + attendEvent.registration_status,
}),
};
}

// conditions to check a user into events during hackathon
const hackEvent = event.body.event;

Expand Down
41 changes: 34 additions & 7 deletions src/functions/update/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import * as dotenv from 'dotenv';
import { Document, WithId } from 'mongodb';
dotenv.config({ path: path.resolve(process.cwd(), '.env') });

const CHECK_IN_START_DATE = new Date('2024-10-26T10:30:00');
const CHECK_IN_CUT_OFF = new Date(CHECK_IN_START_DATE.getTime() + 3 * 24 * 60 * 60 * 1000); // 3 days after check-in start

const update: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (event) => {
// if user email = auth email, you're updating auth user
// need to follow FSM for registration status
Expand Down Expand Up @@ -67,8 +70,16 @@ const update: ValidatedEventAPIGatewayProxyEvent<typeof schema> = async (event)
}

// validate updates
const isValidUpdates = validateUpdates(event.body.updates, updatedUser.registration_status, updatedUser);
if (!isValidUpdates) {
const validationResult = validateUpdates(event.body.updates, updatedUser.registration_status, updatedUser);
if (typeof validationResult === 'string') {
return {
statusCode: 400,
body: JSON.stringify({
statusCode: 400,
message: validationResult,
}),
};
} else if (!validationResult) {
return {
statusCode: 400,
body: JSON.stringify({
Expand Down Expand Up @@ -135,13 +146,29 @@ function isValidRegistrationStatusUpdate(current: string, goal: string): boolean

// return true or false whether the proposed update is valid or not

function validateUpdates(updates: Updates, registrationStatus?: string, user?: WithId<Document>): boolean {
function validateUpdates(updates: Updates, registrationStatus?: string, user?: WithId<Document>): boolean | string {
const setUpdates = updates.$set;
if (setUpdates) {
if ('registration_status' in setUpdates) {
const currentDate = new Date();
const goalStatus = setUpdates.registration_status as string;
if (!isValidRegistrationStatusUpdate(registrationStatus || 'unregistered', goalStatus)) return false;
//validates for unregistered users going to registered status

if (goalStatus === 'checked_in') {
if (currentDate > CHECK_IN_CUT_OFF)
return `Registration is closed. The cutoff date was ${CHECK_IN_CUT_OFF.toLocaleString()}.`;
}

const atleastRegistered = ['confirmed', 'waitlist', 'registered', 'coming'].includes(
registrationStatus || 'unregistered'
);
if (goalStatus === 'checked_in' && atleastRegistered) {
if (currentDate >= CHECK_IN_START_DATE || registrationStatus === 'confirmed') return true;
else
return `Current status of this user is ${registrationStatus}. Check-in will be available after ${CHECK_IN_START_DATE.toLocaleString()}.`;
}

if (!isValidRegistrationStatusUpdate(registrationStatus || 'unregistered', goalStatus))
return `Invalid registration status update from ${registrationStatus} to ${goalStatus}`;

if ((registrationStatus === undefined || registrationStatus == 'unregistered') && goalStatus === 'registered') {
if (
Expand All @@ -164,11 +191,11 @@ function validateUpdates(updates: Updates, registrationStatus?: string, user?: W
'phone_number',
].some((registrationField) => !user[registrationField] || user[registrationField] === '')
)
return false;
return 'Missing required fields';
} else return true;
}
if (['_id', 'password', 'discord', 'created_at', 'registered_at'].some((lockedProp) => lockedProp in setUpdates))
return false;
return 'Cannot update locked fields';

return true;
}
Expand Down
26 changes: 26 additions & 0 deletions tests/attend-event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ describe('Attend-Event tests', () => {
},
},
},
registration_status: 'checked_in',
})
.mockReturnValueOnce({
role: {
Expand All @@ -117,6 +118,7 @@ describe('Attend-Event tests', () => {
findOneMock
.mockReturnValueOnce({
day_of: {},
registration_status: 'checked_in',
})
.mockReturnValueOnce({
role: {
Expand All @@ -135,4 +137,28 @@ describe('Attend-Event tests', () => {
expect(result.statusCode).toBe(200);
expect(JSON.parse(result.body).message).toBe('user successfully checked into event');
});

it('user tries to attend event when they are not checked_in', async () => {
findOneMock
.mockReturnValueOnce({
day_of: {},
registration_status: 'registered',
})
.mockReturnValueOnce({
role: {
hacker: false,
volunteer: true,
judge: false,
sponsor: false,
mentor: false,
organizer: false,
director: true,
},
});
const mockEvent = createEvent(userData, path, httpMethod);
const result = await main(mockEvent, mockContext, mockCallback);

expect(result.statusCode).toBe(409);
expect(JSON.parse(result.body).message).toBe('User has not checked in. Current status is registered');
});
});
11 changes: 9 additions & 2 deletions tests/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,14 @@ describe('/update endpoint', () => {
const mockEvent = createEvent(invalidUpdate, '/update', 'POST');
const res = await main(mockEvent, mockContext, mockCallback);
expect(res.statusCode).toBe(400);
expect(JSON.parse(res.body).message).toBe('Bad updates.');
/*
The reason this message is being commented out is because with the new error messages,
the error message will be different depending on what field is being updated.

For example, password being update will have different message from registration_status being
updated to a value that is not a part of the graph.
*/
// expect(JSON.parse(res.body).message).toBe('Invalid registration status update from registered to coming');
}
});

Expand Down Expand Up @@ -227,7 +234,7 @@ describe('/update endpoint', () => {
const mockEvent = createEvent(incompleteUserData, '/update', 'POST');
const res = await main(mockEvent, mockContext, mockCallback);
expect(res.statusCode).toBe(400);
expect(JSON.parse(res.body).message).toBe('Bad updates.');
expect(JSON.parse(res.body).message).toBe('Missing required fields');
});
//case 8
it('Completed fields for registration, success', async () => {
Expand Down
Loading