From a03119422d209fc798c5f8d636c0bb60bb6e6d2e Mon Sep 17 00:00:00 2001 From: David Huang Date: Thu, 15 Feb 2024 20:08:17 -0600 Subject: [PATCH 1/4] added util for easier API testing --- middleware.ts | 8 ++++++++ utils/api-testing.ts | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 utils/api-testing.ts diff --git a/middleware.ts b/middleware.ts index d9b9333..afe6fa7 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,3 +1,5 @@ +import { testingAPI } from './utils/api-testing'; + /** * THIS FILE HAS TO STAY HERE! * Use the default next-auth middleware pattern. @@ -12,3 +14,9 @@ export { default } from 'next-auth/middleware'; export const config = { matcher: ['/api/:function*'], }; + +function middleware() {} +// when in development, export the empty middleware function +if (testingAPI) { + module.exports = { ...module.exports, middleware }; +} diff --git a/utils/api-testing.ts b/utils/api-testing.ts new file mode 100644 index 0000000..bb7648c --- /dev/null +++ b/utils/api-testing.ts @@ -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 = true; + +const fakeAdminSession = { + user: { + id: '65ae7bbe24dc37492f2581c2', + }, +}; + +// returns a fake user session when testing the API +export const makeSessionForAPITest = () => { + return testingAPI ? fakeAdminSession : null; +}; From 3387e5827ebd3f3a6a515fdb58116fba4e046815 Mon Sep 17 00:00:00 2001 From: David Huang Date: Thu, 15 Feb 2024 20:08:41 -0600 Subject: [PATCH 2/4] API for event applications --- .../event/[id]/application/[responseId].ts | 87 +++++++++++++++++++ pages/api/event/[id]/applications.ts | 44 ++++++++++ utils/utils.ts | 5 ++ 3 files changed, 136 insertions(+) create mode 100644 pages/api/event/[id]/application/[responseId].ts create mode 100644 pages/api/event/[id]/applications.ts diff --git a/pages/api/event/[id]/application/[responseId].ts b/pages/api/event/[id]/application/[responseId].ts new file mode 100644 index 0000000..ef5a41f --- /dev/null +++ b/pages/api/event/[id]/application/[responseId].ts @@ -0,0 +1,87 @@ +import dbConnect from '@/lib/dbConnect'; +import type { NextApiRequest, NextApiResponse } from 'next'; +import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications'; +import { authOptions } from '@/pages/api/auth/[...nextauth]'; +import { getServerSession } from 'next-auth'; +import { makeSessionForAPITest } from '@/utils/api-testing'; +import ApplicationResponse from 'bookem-shared/src/models/ApplicationResponse'; +import { ApplicationStatus, ApplicationResponseData } from 'bookem-shared/src/types/database'; +import { enumChecking as checkEnum } from '@/utils/utils'; + +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, responseId }, + method, + } = req; + + switch (method) { + /** + * // TODO - change the route comments for both files + * @route GET /api/applications + * @desc Get specific response + * @req event: id, response: responseId + * @res a specific response + */ + case 'GET': + try { + await dbConnect(); + + const applicationResponse = await ApplicationResponse.findOne({ + _id: responseId, + }); + + if (!applicationResponse) { + return res.status(404).json({ message: 'Response not found' }); + } + + return res.status(200).json(applicationResponse); + } catch (error: any) { + console.error(error); + res.status(500).json({ message: error.message }); + } + break; + + case 'PUT': + try { + await dbConnect(); + + const applicationResponse = await ApplicationResponse.findOne({ + _id: responseId, + }); + + if (!applicationResponse) { + return res.status(404).json({ message: 'Response not found' }); + } + + const responseUpdate = req.body as ApplicationResponseData; + + const updateStatus = responseUpdate.status as ApplicationStatus; + // enum checking to ensure status is valid + if (!checkEnum(responseUpdate.status, ApplicationStatus)) { + return res.status(400).json({ message: 'Invalid status' }); + } + + // update the status + await ApplicationResponse.findOneAndUpdate( + { _id: responseId }, + { + status: updateStatus, + } + ); + + return res.status(200).json({ message: 'Response updated' }); + } catch (error: any) { + console.error(error); + res.status(500).json({ message: error.message }); + } + break; + } +} diff --git a/pages/api/event/[id]/applications.ts b/pages/api/event/[id]/applications.ts new file mode 100644 index 0000000..dcdf0a4 --- /dev/null +++ b/pages/api/event/[id]/applications.ts @@ -0,0 +1,44 @@ +import dbConnect from '@/lib/dbConnect'; +import type { NextApiRequest, NextApiResponse } from 'next'; +import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications'; +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 Return a list of questions + a list of responses + * @req event id + * @res a list of questions + a list of responses + */ + case 'GET': + try { + await dbConnect(); + + const applicationWithResponses = await VolunteerApplications.find({ + eventId: id, + }) + + return res.status(200).json(applicationWithResponses); + } catch (error: any) { + console.error(error); + res.status(500).json({ message: error.message }); + } + break; + } +} diff --git a/utils/utils.ts b/utils/utils.ts index 95b0e9d..b62db2d 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -1,5 +1,10 @@ import * as XLSX from 'xlsx'; import { saveAs } from 'file-saver'; + +export const enumChecking = (value: string, enumType: any) => { + return Object.values(enumType).includes(value); +} + export const convertToDate = (str: string) => { if (str === '') return str; const date = new Date(str); From 4897d8feedbbaaf82ac891cf70dd834270ea1281 Mon Sep 17 00:00:00 2001 From: David Huang Date: Thu, 15 Feb 2024 20:10:53 -0600 Subject: [PATCH 3/4] comments --- pages/api/event/[id]/application/[responseId].ts | 9 +++++++-- pages/api/event/[id]/applications.ts | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pages/api/event/[id]/application/[responseId].ts b/pages/api/event/[id]/application/[responseId].ts index ef5a41f..30a0e9e 100644 --- a/pages/api/event/[id]/application/[responseId].ts +++ b/pages/api/event/[id]/application/[responseId].ts @@ -24,8 +24,7 @@ export default async function handler( switch (method) { /** - * // TODO - change the route comments for both files - * @route GET /api/applications + * @route GET /api/event/[id]/application/[responseId] * @desc Get specific response * @req event: id, response: responseId * @res a specific response @@ -49,6 +48,12 @@ export default async function handler( } break; + /** + * @route PUT /api/event/[id]/application/[responseId] + * @desc update the status of a response + * @req event: id, response: responseId + * @res a message telling whether the response is updated + */ case 'PUT': try { await dbConnect(); diff --git a/pages/api/event/[id]/applications.ts b/pages/api/event/[id]/applications.ts index dcdf0a4..0360eba 100644 --- a/pages/api/event/[id]/applications.ts +++ b/pages/api/event/[id]/applications.ts @@ -21,7 +21,7 @@ export default async function handler( switch (method) { /** - * @route GET /api/applications + * @route GET /api/event/applications * @desc Return a list of questions + a list of responses * @req event id * @res a list of questions + a list of responses From 73f34bc9e2d615a8e9497cacfb49e241c2ae1f31 Mon Sep 17 00:00:00 2001 From: David Huang Date: Thu, 15 Feb 2024 20:17:09 -0600 Subject: [PATCH 4/4] remove unused code & format document --- pages/api/event/[id]/application/[responseId].ts | 13 ++++--------- pages/api/event/[id]/applications.ts | 9 +-------- utils/utils.ts | 2 +- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/pages/api/event/[id]/application/[responseId].ts b/pages/api/event/[id]/application/[responseId].ts index 30a0e9e..740d81c 100644 --- a/pages/api/event/[id]/application/[responseId].ts +++ b/pages/api/event/[id]/application/[responseId].ts @@ -1,21 +1,16 @@ import dbConnect from '@/lib/dbConnect'; import type { NextApiRequest, NextApiResponse } from 'next'; -import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications'; -import { authOptions } from '@/pages/api/auth/[...nextauth]'; -import { getServerSession } from 'next-auth'; -import { makeSessionForAPITest } from '@/utils/api-testing'; import ApplicationResponse from 'bookem-shared/src/models/ApplicationResponse'; -import { ApplicationStatus, ApplicationResponseData } from 'bookem-shared/src/types/database'; +import { + ApplicationStatus, + ApplicationResponseData, +} from 'bookem-shared/src/types/database'; import { enumChecking as checkEnum } from '@/utils/utils'; 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, responseId }, diff --git a/pages/api/event/[id]/applications.ts b/pages/api/event/[id]/applications.ts index 0360eba..8da682e 100644 --- a/pages/api/event/[id]/applications.ts +++ b/pages/api/event/[id]/applications.ts @@ -1,18 +1,11 @@ import dbConnect from '@/lib/dbConnect'; import type { NextApiRequest, NextApiResponse } from 'next'; import VolunteerApplications from 'bookem-shared/src/models/VolunteerApplications'; -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 }, @@ -32,7 +25,7 @@ export default async function handler( const applicationWithResponses = await VolunteerApplications.find({ eventId: id, - }) + }); return res.status(200).json(applicationWithResponses); } catch (error: any) { diff --git a/utils/utils.ts b/utils/utils.ts index b62db2d..19814ad 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -3,7 +3,7 @@ import { saveAs } from 'file-saver'; export const enumChecking = (value: string, enumType: any) => { return Object.values(enumType).includes(value); -} +}; export const convertToDate = (str: string) => { if (str === '') return str;