Update eslint config, brewery post controllers

This commit is contained in:
Aaron William Po
2023-12-10 12:47:09 -05:00
parent 38ecd3a5fb
commit 830e9dc845
21 changed files with 372 additions and 255 deletions

View File

@@ -3,11 +3,11 @@ import addBeerImageToDB from '@/services/BeerImage/addBeerImageToDB';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import { z } from 'zod';
import { UploadBeerPostImagesRequest } from './types';
import { UploadImagesRequest } from '../types';
// eslint-disable-next-line import/prefer-default-export
export const processBeerImageData = async (
req: UploadBeerPostImagesRequest,
req: UploadImagesRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { files, user, body } = req;

View File

@@ -0,0 +1,34 @@
import ServerError from '@/config/util/ServerError';
import addBreweryImageToDB from '@/services/BreweryImage/addBreweryImageToDB';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import { z } from 'zod';
import { UploadImagesRequest } from '../types';
// eslint-disable-next-line import/prefer-default-export
export const processBreweryImageData = async (
req: UploadImagesRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { files, user, body } = req;
if (!files || !files.length) {
throw new ServerError('No images uploaded', 400);
}
const breweryImages = await addBreweryImageToDB({
alt: body.alt,
caption: body.caption,
breweryPostId: req.query.id,
userId: user!.id,
files,
});
res.status(200).json({
success: true,
message: `Successfully uploaded ${breweryImages.length} image${
breweryImages.length > 1 ? 's' : ''
}`,
statusCode: 200,
});
};

View File

@@ -2,7 +2,7 @@ import { UserExtendedNextApiRequest } from '@/config/auth/types';
import ImageMetadataValidationSchema from '@/services/schema/ImageSchema/ImageMetadataValidationSchema';
import { z } from 'zod';
export interface UploadBeerPostImagesRequest extends UserExtendedNextApiRequest {
export interface UploadImagesRequest extends UserExtendedNextApiRequest {
files?: Express.Multer.File[];
query: { id: string };
body: z.infer<typeof ImageMetadataValidationSchema>;

View File

@@ -0,0 +1,94 @@
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import ServerError from '@/config/util/ServerError';
import DBClient from '@/prisma/DBClient';
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse, NextApiRequest } from 'next';
import { z } from 'zod';
export const sendBreweryPostLikeRequest = async (
req: UserExtendedNextApiRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const id = req.query.id! as string;
const user = req.user!;
const breweryPost = await DBClient.instance.breweryPost.findUnique({
where: { id },
});
if (!breweryPost) {
throw new ServerError('Could not find a brewery post with that id', 404);
}
const alreadyLiked = await DBClient.instance.breweryPostLike.findFirst({
where: { breweryPostId: breweryPost.id, likedById: user.id },
});
const jsonResponse = {
success: true as const,
message: '',
statusCode: 200 as const,
};
if (alreadyLiked) {
await DBClient.instance.breweryPostLike.delete({
where: { id: alreadyLiked.id },
});
jsonResponse.message = 'Successfully unliked brewery post';
} else {
await DBClient.instance.breweryPostLike.create({
data: { breweryPostId: breweryPost.id, likedById: user.id },
});
jsonResponse.message = 'Successfully liked brewery post';
}
res.status(200).json(jsonResponse);
};
export const getBreweryPostLikeCount = async (
req: NextApiRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const id = req.query.id! as string;
const breweryPost = await DBClient.instance.breweryPost.findUnique({
where: { id },
});
if (!breweryPost) {
throw new ServerError('Could not find a brewery post with that id', 404);
}
const likeCount = await DBClient.instance.breweryPostLike.count({
where: { breweryPostId: breweryPost.id },
});
res.status(200).json({
success: true,
message: 'Successfully retrieved like count',
statusCode: 200,
payload: { likeCount },
});
};
export const getBreweryPostLikeStatus = async (
req: UserExtendedNextApiRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const user = req.user!;
const id = req.query.id as string;
const alreadyLiked = await DBClient.instance.breweryPostLike.findFirst({
where: {
breweryPostId: id,
likedById: user.id,
},
});
res.status(200).json({
success: true,
message: alreadyLiked ? 'Brewery post is liked.' : 'Brewery post is not liked.',
statusCode: 200,
payload: { isLiked: !!alreadyLiked },
});
};

View File

@@ -18,7 +18,7 @@ import {
GetAllBeerPostsRequest,
GetBeerRecommendationsRequest,
} from './types';
import { GetPostsByUserIdRequest } from '../types';
import { GetAllPostsByConnectedPostId } from '../types';
export const checkIfBeerPostOwner = async <BeerPostRequestType extends BeerPostRequest>(
req: BeerPostRequestType,
@@ -145,7 +145,7 @@ export const createBeerPost = async (
};
export const getBeerPostsByUserId = async (
req: GetPostsByUserIdRequest,
req: GetAllPostsByConnectedPostId,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const pageNum = parseInt(req.query.page_num, 10);

View File

@@ -10,13 +10,8 @@ import getBeerPostsByBeerStyleId from '@/services/BeerPost/getBeerPostsByBeerSty
import getAllBeerStyles from '@/services/BeerStyles/getAllBeerStyles';
import ServerError from '@/config/util/ServerError';
import {
CreateBeerStyleRequest,
GetAllBeersByBeerStyleRequest,
GetBeerStyleByIdRequest,
} from './types';
import { GetAllPostsRequest } from '../types';
import { CreateBeerStyleRequest, GetBeerStyleByIdRequest } from './types';
import { GetAllPostsByConnectedPostId, GetAllPostsRequest } from '../types';
export const getBeerStyle = async (
req: GetBeerStyleByIdRequest,
@@ -35,7 +30,7 @@ export const getBeerStyle = async (
};
export const getAllBeersByBeerStyle = async (
req: GetAllBeersByBeerStyleRequest,
req: GetAllPostsByConnectedPostId,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
// eslint-disable-next-line @typescript-eslint/naming-convention

View File

@@ -1,6 +1,5 @@
import { NextApiRequest } from 'next';
import { GetAllPostsRequest } from '@/controllers/posts/types';
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import { z } from 'zod';
import CreateBeerStyleValidationSchema from '@/services/BeerStyles/schema/CreateBeerStyleValidationSchema';
@@ -9,9 +8,6 @@ export interface GetBeerStyleByIdRequest extends NextApiRequest {
query: { id: string };
}
export interface GetAllBeersByBeerStyleRequest extends GetAllPostsRequest {
query: { page_size: string; page_num: string; id: string };
}
export interface CreateBeerStyleRequest extends UserExtendedNextApiRequest {
body: z.infer<typeof CreateBeerStyleValidationSchema>;
}

View File

@@ -3,11 +3,17 @@ import getAllBreweryPostsByPostedById from '@/services/BreweryPost/getAllBrewery
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
import { NextApiResponse } from 'next';
import { z } from 'zod';
import { GetPostsByUserIdRequest } from '../types';
import getAllBreweryPosts from '@/services/BreweryPost/getAllBreweryPosts';
import createNewBreweryPost from '@/services/BreweryPost/createNewBreweryPost';
import geocode from '@/config/mapbox/geocoder';
import ServerError from '@/config/util/ServerError';
import BreweryPostMapQueryResult from '@/services/BreweryPost/schema/BreweryPostMapQueryResult';
import BeerPostQueryResult from '@/services/BeerPost/schema/BeerPostQueryResult';
import { CreateBreweryPostRequest, GetBreweryPostsRequest } from './types';
import { GetAllPostsByConnectedPostId } from '../types';
// eslint-disable-next-line import/prefer-default-export
export const getBreweryPostsByUserId = async (
req: GetPostsByUserIdRequest,
req: GetAllPostsByConnectedPostId,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const pageNum = parseInt(req.query.page_num, 10);
@@ -34,3 +40,154 @@ export const getBreweryPostsByUserId = async (
success: true,
});
};
export const getBreweryPosts = async (
req: GetBreweryPostsRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const pageNum = parseInt(req.query.page_num, 10);
const pageSize = parseInt(req.query.page_size, 10);
const breweryPosts = await getAllBreweryPosts({ pageNum, pageSize });
const breweryPostCount = await DBClient.instance.breweryPost.count();
res.setHeader('X-Total-Count', breweryPostCount);
res.status(200).json({
message: 'Brewery posts retrieved successfully',
statusCode: 200,
payload: breweryPosts,
success: true,
});
};
export const createBreweryPost = async (
req: CreateBreweryPostRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const { name, description, dateEstablished, address, city, country, region } = req.body;
const userId = req.user!.id;
const fullAddress = `${address}, ${city}, ${region}, ${country}`;
const geocoded = await geocode(fullAddress);
if (!geocoded) {
throw new ServerError('Address is not valid', 400);
}
const [latitude, longitude] = geocoded.center;
const location = await DBClient.instance.breweryLocation.create({
data: {
address,
city,
country,
stateOrProvince: region,
coordinates: [latitude, longitude],
postedBy: { connect: { id: userId } },
},
select: { id: true },
});
const newBreweryPost = await createNewBreweryPost({
name,
description,
locationId: location.id,
dateEstablished,
userId,
});
res.status(201).json({
message: 'Brewery post created successfully',
statusCode: 201,
payload: newBreweryPost,
success: true,
});
};
export const getMapBreweryPosts = async (
req: GetBreweryPostsRequest,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
const pageNum = parseInt(req.query.page_num, 10);
const pageSize = parseInt(req.query.page_size, 10);
const skip = (pageNum - 1) * pageSize;
const take = pageSize;
const breweryPosts: z.infer<typeof BreweryPostMapQueryResult>[] =
await DBClient.instance.breweryPost.findMany({
select: {
location: {
select: { coordinates: true, city: true, country: true, stateOrProvince: true },
},
id: true,
name: true,
},
skip,
take,
});
const breweryPostCount = await DBClient.instance.breweryPost.count();
res.setHeader('X-Total-Count', breweryPostCount);
res.status(200).json({
message: 'Brewery posts retrieved successfully',
statusCode: 200,
payload: breweryPosts,
success: true,
});
};
export const getAllBeersByBrewery = async (
req: GetAllPostsByConnectedPostId,
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
) => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { page_size, page_num, id } = req.query;
const pageNum = parseInt(page_num, 10);
const pageSize = parseInt(page_size, 10);
const beers: z.infer<typeof BeerPostQueryResult>[] =
await DBClient.instance.beerPost.findMany({
where: { breweryId: id },
skip: (pageNum - 1) * pageSize,
take: pageSize,
select: {
id: true,
name: true,
ibu: true,
abv: true,
createdAt: true,
updatedAt: true,
description: true,
postedBy: { select: { username: true, id: true } },
brewery: { select: { name: true, id: true } },
style: { select: { name: true, id: true, description: true } },
beerImages: {
select: {
alt: true,
path: true,
caption: true,
id: true,
createdAt: true,
updatedAt: true,
},
},
},
});
const count = await DBClient.instance.beerPost.count({
where: { breweryId: id },
});
res.setHeader('X-Total-Count', count);
res.status(200).json({
message: 'Beers fetched successfully',
statusCode: 200,
payload: beers,
success: true,
});
};

View File

@@ -0,0 +1,13 @@
import { UserExtendedNextApiRequest } from '@/config/auth/types';
import CreateBreweryPostSchema from '@/services/BreweryPost/schema/CreateBreweryPostSchema';
import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema';
import { NextApiRequest } from 'next';
import { z } from 'zod';
export interface GetBreweryPostsRequest extends NextApiRequest {
query: z.infer<typeof PaginatedQueryResponseSchema>;
}
export interface CreateBreweryPostRequest extends UserExtendedNextApiRequest {
body: z.infer<typeof CreateBreweryPostSchema>;
}

View File

@@ -1,9 +1,38 @@
import { NextApiRequest } from 'next';
/** Represents the request object for getting all posts. */
export interface GetAllPostsRequest extends NextApiRequest {
query: { page_size: string; page_num: string };
}
export interface GetPostsByUserIdRequest extends NextApiRequest {
/**
* Represents the request object for getting all posts by a connected post ID.
*
* This may include:
*
* - All beers by a brewery ID
* - All beers by a beer style ID
* - All beer styles by a user ID
* - And more...
*
* @example
* const getAllBeersByBeerStyle = async (
* req: GetAllPostsByConnectedPostId,
* res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
* ) => {
* const { page_size, page_num, id } = req.query;
* // ...
* };
*
* @example
* const getAllBeersByUserId = async (
* req: GetAllPostsByConnectedPostId,
* res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
* ) => {
* const { page_size, page_num, id } = req.query;
* // ...
* };
*/
export interface GetAllPostsByConnectedPostId extends NextApiRequest {
query: { id: string; page_size: string; page_num: string };
}