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

Event application api #81

Merged
merged 9 commits into from
Feb 12, 2024
9 changes: 7 additions & 2 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { testingAPI } from './utils/api-testing';

/**
* THIS FILE HAS TO STAY HERE!
* Use the default next-auth middleware pattern from https://next-auth.js.org/configuration/nextjs
Expand All @@ -16,5 +18,8 @@ export const config = {
matcher: ['/api/((?!users/create).*)'],
};

// Comment everything and uncomment this to test
// export function middleware() {}
function middleware() {}
// when in development, export the empty middleware function
if (testingAPI) {
module.exports = { ...module.exports, middleware };
}
56 changes: 56 additions & 0 deletions pages/api/applications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import dbConnect from '@/lib/dbConnect';
import { ObjectId } from 'mongodb';
import type { NextApiRequest, NextApiResponse } from 'next';
import mongoose from 'mongoose';
import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications';
import { ApplicationResponseData } from 'bookem-shared/src/types/database';
import ApplicationResponse from 'bookem-shared/src/models/ApplicationResponse';
import VolunteerEvents from 'bookem-shared/src/models/VolunteerEvents';
import { authOptions } from '@/pages/api/auth/[...nextauth]';
import { getServerSession } from 'next-auth';
import { makeSessionForAPITest } from '@/utils/api-testing';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Get session user
const session =
(await getServerSession(req, res, authOptions)) || makeSessionForAPITest();

// Get request parameter
const {
query: { id },
method,
} = req;

switch (method) {
/**
* @route GET /api/applications
* @desc Get all applications to all applied events for a user
* @req event id, user in session
* @res list of applied events
*/
case 'GET':
try {
await dbConnect();
await VolunteerEvents.find({});

// query volunteerApplication by event id attributes
const applicationResponses = await ApplicationResponse.find({
userId: session.user.id,
}).populate('eventId');

// get all the events that the user has applied to
const events = applicationResponses.map(response => {
return response.eventId;
});

return res.status(200).json({ message: events });
} catch (error: any) {
console.error(error);
res.status(500).json({ message: error.message });
}
break;
}
}
108 changes: 108 additions & 0 deletions pages/api/event/[id]/apply.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import dbConnect from '@/lib/dbConnect';
import { ObjectId } from 'mongodb';
import type { NextApiRequest, NextApiResponse } from 'next';
import mongoose from 'mongoose';
import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications';
import { ApplicationResponseData } from 'bookem-shared/src/types/database';
import ApplicationResponse from 'bookem-shared/src/models/ApplicationResponse';
import { authOptions } from '@/pages/api/auth/[...nextauth]';
import { getServerSession } from 'next-auth';
import { makeSessionForAPITest } from '@/utils/api-testing';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Get session user
let session =
(await getServerSession(req, res, authOptions)) || makeSessionForAPITest();

// Get request parameter
const {
query: { id },
method,
} = req;

switch (method) {
/**
* @route GET /api/event/[id]/apply
* @desc Return a list of application questions that this event needs
* @req event id, user in session
* @res list of application questions
*/
case 'GET':
try {
await dbConnect();

if (!id) return res.status(400).json({ message: 'Missing id' });

// check if id is a valid mongoose id
if (!ObjectId.isValid(id as string))
return res.status(400).json({ message: 'Invalid id' });

// query volunteerApplication by event id attributes
const volunteerApplication = await VolunteerApplications.findOne({
eventId: id,
});

if (!volunteerApplication) {
return res
.status(404)
.json({ message: 'No application for the event found' });
}

const questions = volunteerApplication.questions;

return res.status(200).json({ message: questions });
} catch (error) {
console.error(error);
res.status(500).json({ message: error });
}
break;

/**
* @route POST /api/event/[id]/apply
* @desc Submit the answers to the questions this event needs
* @req event id, user in session
* @res Success message
*/
case 'POST':
try {
await dbConnect();

const response = req.body as ApplicationResponseData;
const { answers } = response;

// Declare the following ops to be an atomic transaction
const mongoSession = await mongoose.startSession();
await mongoSession.withTransaction(async () => {
// insert the response to applicationResponses data
const newResponse = new ApplicationResponse({
userId: session.user.id,
status: 'pending',
eventId: id,
answers,
});

await newResponse.save();

// use the id of the saved response to update the volunteerApplications data
await VolunteerApplications.updateOne(
{ eventId: id },
{
$push: {
responses: newResponse._id,
},
}
);
});

return res.status(200).json('Application Submitted');
} catch (error: any) {
res.status(500).json({ message: error.message });
console.error(error);
}

break;
}
}
61 changes: 61 additions & 0 deletions pages/api/event/[id]/submitted-application.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import dbConnect from '@/lib/dbConnect';
import { ObjectId } from 'mongodb';
import type { NextApiRequest, NextApiResponse } from 'next';
import ApplicationResponse from 'bookem-shared/src/models/ApplicationResponse';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/pages/api/auth/[...nextauth]';
import { makeSessionForAPITest } from '@/utils/api-testing';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// Get session user
let session =
(await getServerSession(req, res, authOptions)) || makeSessionForAPITest();

// Get request parameter
const {
query: { id },
method,
} = req;

switch (method) {
/**
* @route GET /api/event/[id]/submitted-application
* @desc Get submitted application
* @req event id, user in session
* @res list of application questions
*/
case 'GET':
try {
await dbConnect();

if (!id) return res.status(400).json({ message: 'Missing id' });

// check if id is a valid mongoose id
if (!ObjectId.isValid(id as string))
return res.status(400).json({ message: 'Invalid id' });

// query volunteerApplication by event id attributes
// using findOne - assuming there is only one application per event per user
const volunteerApplication = await ApplicationResponse.findOne({
userId: session.user.id,
eventId: id,
});

// TODO - refactor a common util for when something is not found
if (!volunteerApplication) {
return res
.status(404)
.json({ message: 'No application for the event found' });
}

return res.status(200).json({ message: volunteerApplication });
} catch (error: any) {
console.error(error);
res.status(500).json({ message: error });
}
break;
}
}
15 changes: 15 additions & 0 deletions utils/api-testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// common utils for simple API testing in development phase

// change this var to true when you are testing the API endpoints without logging in
export const testingAPI = false;

const fakeUserSession = {
user: {
id: '65ae7bbd24dc37492f2581c0',
},
};

// returns a fake user session when testing the API
export const makeSessionForAPITest = () => {
return testingAPI ? fakeUserSession : null;
};
Loading