Update api routes to use authenticated user

This commit is contained in:
Aaron William Po
2023-02-06 19:01:01 -05:00
parent 9a9d8bcb94
commit 3626e3de44
12 changed files with 190 additions and 143 deletions

View File

@@ -1,27 +1,31 @@
import validateRequest from '@/config/zod/middleware/validateRequest';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import ServerError from '@/config/util/ServerError';
import createNewBeerComment from '@/services/BeerComment/createNewBeerComment';
import { BeerCommentQueryResultT } from '@/services/BeerComment/schema/BeerCommentQueryResult';
import BeerCommentValidationSchema from '@/services/BeerComment/schema/CreateBeerCommentValidationSchema';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiHandler } from 'next';
import nextConnect from 'next-connect';
import { z } from 'zod';
import getCurrentUser from '@/config/auth/middleware/getCurrentUser';
import { NextApiResponse } from 'next';
const createComment: NextApiHandler<z.infer<typeof APIResponseValidationSchema>> = async (
req,
res,
interface CreateCommentRequest extends UserExtendedNextApiRequest {
body: z.infer<typeof BeerCommentValidationSchema>;
}
const createComment = async (
req: CreateCommentRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const cleanedReqBody = BeerCommentValidationSchema.safeParse(req.body);
if (!cleanedReqBody.success) {
throw new ServerError('Invalid request body', 400);
}
const { content, rating, beerPostId } = cleanedReqBody.data;
const { content, rating, beerPostId } = req.body;
const newBeerComment: BeerCommentQueryResultT = await createNewBeerComment({
content,
rating,
beerPostId,
userId: req.user!.id,
});
res.status(201).json({
@@ -32,6 +36,10 @@ const createComment: NextApiHandler<z.infer<typeof APIResponseValidationSchema>>
});
};
const handler = nextConnect(NextConnectConfig).post(createComment);
const handler = nextConnect(NextConnectConfig).post(
validateRequest({ bodySchema: BeerCommentValidationSchema }),
getCurrentUser,
createComment,
);
export default handler;

View File

@@ -1,21 +1,24 @@
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import validateRequest from '@/config/zod/middleware/validateRequest';
import nextConnect from 'next-connect';
import ServerError from '@/config/util/ServerError';
import createNewBeerPost from '@/services/BeerPost/createNewBeerPost';
import BeerPostValidationSchema from '@/services/BeerPost/schema/CreateBeerPostValidationSchema';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiHandler } from 'next';
import { NextApiResponse } from 'next';
import { z } from 'zod';
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import getCurrentUser from '@/config/auth/middleware/getCurrentUser';
const createBeerPost: NextApiHandler<
z.infer<typeof APIResponseValidationSchema>
> = async (req, res) => {
const cleanedReqBody = BeerPostValidationSchema.safeParse(req.body);
if (!cleanedReqBody.success) {
throw new ServerError('Invalid request body', 400);
}
interface CreateBeerPostRequest extends UserExtendedNextApiRequest {
body: z.infer<typeof BeerPostValidationSchema>;
}
const createBeerPost = async (
req: CreateBeerPostRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { name, description, typeId, abv, ibu, breweryId } = req.body;
const { name, description, typeId, abv, ibu, breweryId } = cleanedReqBody.data;
const newBeerPost = await createNewBeerPost({
name,
description,
@@ -23,6 +26,7 @@ const createBeerPost: NextApiHandler<
ibu,
typeId,
breweryId,
userId: req.user!.id,
});
res.status(201).json({
@@ -33,6 +37,10 @@ const createBeerPost: NextApiHandler<
});
};
const handler = nextConnect(NextConnectConfig).post(createBeerPost);
const handler = nextConnect(NextConnectConfig).post(
validateRequest({ bodySchema: BeerPostValidationSchema }),
getCurrentUser,
createBeerPost,
);
export default handler;

View File

@@ -1,12 +1,12 @@
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import { ExtendedNextApiRequest } from '@/config/auth/types';
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import getCurrentUser from '@/config/auth/middleware/getCurrentUser';
import nextConnect from 'next-connect';
import { z } from 'zod';
const sendCurrentUser = async (req: ExtendedNextApiRequest, res: NextApiResponse) => {
const sendCurrentUser = async (req: UserExtendedNextApiRequest, res: NextApiResponse) => {
const { user } = req;
res.status(200).json({
message: `Currently logged in as ${user!.username}`,
@@ -17,7 +17,7 @@ const sendCurrentUser = async (req: ExtendedNextApiRequest, res: NextApiResponse
};
const handler = nextConnect<
ExtendedNextApiRequest,
UserExtendedNextApiRequest,
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
>(NextConnectConfig).get(getCurrentUser, sendCurrentUser);

View File

@@ -8,20 +8,19 @@ import { NextApiResponse } from 'next';
import { z } from 'zod';
import ServerError from '@/config/util/ServerError';
import LoginValidationSchema from '@/services/user/schema/LoginValidationSchema';
import { ExtendedNextApiRequest } from '../../../config/auth/types';
import { UserExtendedNextApiRequest } from '../../../config/auth/types';
export default nextConnect<
ExtendedNextApiRequest,
UserExtendedNextApiRequest,
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
>(NextConnectConfig)
.use(passport.initialize())
.use(async (req, res, next) => {
passport.use(localStrat);
const parsed = LoginValidationSchema.safeParse(req.body);
if (!parsed.success) {
throw new ServerError('Username and password are required.', 400);
}
passport.use(localStrat);
passport.authenticate('local', { session: false }, (error, token) => {
if (error) {
next(error);

View File

@@ -1,44 +1,18 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { z } from 'zod';
import ServerError from '@/config/util/ServerError';
import nc, { NextHandler } from 'next-connect';
import nc from 'next-connect';
import createNewUser from '@/services/user/createNewUser';
import CreateUserValidationSchema from '@/services/user/schema/CreateUserValidationSchema';
import NextConnectConfig from '@/config/nextConnect/NextConnectConfig';
import findUserByUsername from '@/services/user/findUserByUsername';
import findUserByEmail from '@/services/user/findUserByEmail';
import validateRequest from '@/config/zod/middleware/validateRequest';
interface RegisterUserRequest extends NextApiRequest {
body: z.infer<typeof CreateUserValidationSchema>;
}
const validateRequest =
({
bodySchema,
querySchema,
}: {
bodySchema?: z.ZodSchema<any>;
querySchema?: z.ZodSchema<any>;
}) =>
async (req: NextApiRequest, res: NextApiResponse, next: NextHandler) => {
if (bodySchema) {
const parsed = bodySchema.safeParse(req.body);
if (!parsed.success) {
throw new ServerError('Invalid request body.', 400);
}
}
if (querySchema) {
const parsed = querySchema.safeParse(req.query);
if (!parsed.success) {
throw new ServerError(parsed.error.message, 400);
}
req.query = parsed.data;
}
next();
};
const registerUser = async (req: RegisterUserRequest, res: NextApiResponse) => {
const [usernameTaken, emailTaken] = await Promise.all([
findUserByUsername(req.body.username),

View File

@@ -1,82 +1,9 @@
import { NextPage } from 'next';
import { SubmitHandler, useForm } from 'react-hook-form';
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import FormError from '@/components/ui/forms/FormError';
import FormInfo from '@/components/ui/forms/FormInfo';
import FormLabel from '@/components/ui/forms/FormLabel';
import FormSegment from '@/components/ui/forms/FormSegment';
import FormTextInput from '@/components/ui/forms/FormTextInput';
import Layout from '@/components/ui/Layout';
import LoginValidationSchema from '@/services/user/schema/LoginValidationSchema';
import sendLoginUserRequest from '@/requests/sendLoginUserRequest';
import useUser from '@/hooks/useUser';
type LoginT = z.infer<typeof LoginValidationSchema>;
const LoginForm = () => {
const router = useRouter();
const { register, handleSubmit, formState } = useForm<LoginT>({
resolver: zodResolver(LoginValidationSchema),
defaultValues: {
username: '',
password: '',
},
});
const { errors } = formState;
const onSubmit: SubmitHandler<LoginT> = async (data) => {
try {
const response = await sendLoginUserRequest(data);
router.push(`/users/${response.id}`);
} catch (error) {
console.error(error);
}
};
return (
<form className="form-control w-9/12 space-y-5" onSubmit={handleSubmit(onSubmit)}>
<div>
<FormInfo>
<FormLabel htmlFor="username">username</FormLabel>
<FormError>{errors.username?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextInput
id="username"
type="text"
formValidationSchema={register('username')}
error={!!errors.username}
placeholder="username"
/>
</FormSegment>
<FormInfo>
<FormLabel htmlFor="password">password</FormLabel>
<FormError>{errors.password?.message}</FormError>
</FormInfo>
<FormSegment>
<FormTextInput
id="password"
type="password"
formValidationSchema={register('password')}
error={!!errors.password}
placeholder="password"
/>
</FormSegment>
</div>
<div className="w-full">
<button type="submit" className="btn-primary btn w-full">
Login
</button>
</div>
</form>
);
};
import LoginForm from '@/components/Login/LoginForm';
const LoginPage: NextPage = () => {
const { user } = useUser();
@@ -88,7 +15,7 @@ const LoginPage: NextPage = () => {
}
router.push(`/user/current`);
}, [user]);
}, [user, router]);
return (
<Layout>