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

refactor: review 컨트롤러 스키마 zod로 변경 #539

Merged
merged 4 commits into from
Jun 28, 2023
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
126 changes: 81 additions & 45 deletions backend/src/reviews/controller/reviews.controller.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,116 @@
import {
Request, Response,
Request, RequestHandler, Response,
} from 'express';
import * as status from 'http-status';
import * as errorCheck from './utils/errorCheck';
import * as parseCheck from './utils/parseCheck';
import { contentParseCheck } from './utils/errorCheck';
import ReviewsService from '../service/reviews.service';
import {
createReviewsSchema,
deleteReviewsSchema,
getReviewsSchema,
patchReviewsSchema,
queryOptionSchema,
userSchema,
} from './reviews.type';
import ErrorResponse from '../../utils/error/errorResponse';
import * as errorCode from '../../utils/error/errorCode';

const reviewsService = new ReviewsService();

export const createReviews = async (
req: Request,
res: Response,
) => {
const { id: tokenId } = req.user as any;
const bookInfoId = req?.body?.bookInfoId;
const content = req?.body?.content;
contentParseCheck(content);
await reviewsService.createReviews(tokenId, bookInfoId, content);
export const createReviews: RequestHandler = async (req, res, next) => {
const parsedId = userSchema.safeParse(req.user);
const parsedBody = createReviewsSchema.safeParse(req.body);

if (!parsedId.success) {
return next(new ErrorResponse(errorCode.NO_MATCHING_USER, 400));
}
if (!parsedBody.success) {
return next(new ErrorResponse(errorCode.INVALID_INPUT_REVIEWS_CONTENT, 400));
}

const { id } = parsedId.data;
const { bookInfoId, content } = parsedBody.data;

await reviewsService.createReviews(id, bookInfoId, content);
return res.status(status.OK).send();
};

export const getReviews = async (
req: Request,
res: Response,
) => {
const { id: tokenId } = req.user as any;
const isMyReview = parseCheck.booleanQueryParse(req.query.isMyReview);
const titleOrNickname = parseCheck.stringQueryParse(req?.query?.titleOrNickname);
const disabled = parseCheck.disabledParse(Number(req?.query?.disabled));
const page = parseCheck.pageParse(parseInt(String(req?.query?.page), 10));
const sort = parseCheck.sortParse(req?.query?.sort);
const limit = parseCheck.limitParse(parseInt(String(req?.query?.limit), 10));
export const getReviews: RequestHandler = async (req, res, next) => {
const parsedId = userSchema.safeParse(req.user);
const parsedQuery = getReviewsSchema.safeParse(req.query);
if (!parsedId.success) {
return next(new ErrorResponse(errorCode.NO_MATCHING_USER, 400));
}
if (!parsedQuery.success) {
return next(new ErrorResponse(errorCode.INVALID_INPUT, 400));
}

const { id } = parsedId.data;
const {
isMyReview, titleOrNickname, disabled, page, sort, limit,
} = parsedQuery.data;

return res
.status(status.OK)
.json(await reviewsService.getReviewsPage(
tokenId,
id,
isMyReview,
titleOrNickname,
titleOrNickname ?? '',
disabled,
page,
sort,
limit,
));
};

export const updateReviews = async (
req: Request,
res: Response,
) => {
const { id: tokenUserId } = req.user as any;
export const updateReviews: RequestHandler = async (req, res, next) => {
const parsedId = userSchema.safeParse(req.user);
if (!parsedId.success) {
return next(new ErrorResponse(errorCode.NO_MATCHING_USER, 400));
}
const { id } = parsedId.data;

const content = errorCheck.contentParseCheck(req?.body?.content);
const reviewsId = errorCheck.reviewsIdParseCheck(req?.params?.reviewsId);
await reviewsService.updateReviews(reviewsId, tokenUserId, content);

await reviewsService.updateReviews(reviewsId, id, content);
return res.status(status.OK).send();
};

export const deleteReviews = async (
req: Request,
res: Response,
) => {
const { id: tokenId } = req.user as any;
const reviewsId = errorCheck.reviewsIdParseCheck(req?.params?.reviewsId);
export const deleteReviews: RequestHandler = async (req, res, next) => {
const parsedId = userSchema.safeParse(req.user);
const parsedParams = deleteReviewsSchema.safeParse(req.params);
if (!parsedId.success) {
return next(new ErrorResponse(errorCode.NO_MATCHING_USER, 400));
}
if (!parsedParams.success) {
return next(new ErrorResponse(errorCode.INVALID_INPUT_REVIEWS_ID, 400));
}
const { id } = parsedId.data;
const { reviewsId } = parsedParams.data;

const reviewsUserId = await errorCheck.reviewsIdExistCheck(reviewsId);
errorCheck.idAndTokenIdSameCheck(reviewsUserId, tokenId);
await reviewsService.deleteReviews(reviewsId, tokenId);
errorCheck.idAndTokenIdSameCheck(reviewsUserId, id);

await reviewsService.deleteReviews(reviewsId, id);
return res.status(status.OK).send();
};

export const patchReviews = async (
req: Request,
res: Response,
) => {
const { id: tokenId } = req.user as any;
const reviewsId = errorCheck.reviewsIdParseCheck(req?.params?.reviewsId);
export const patchReviews: RequestHandler = async (req, res, next) => {
const parsedId = userSchema.safeParse(req.user);
const parsedParams = patchReviewsSchema.safeParse(req.params);
if (!parsedId.success) {
return next(new ErrorResponse(errorCode.NO_MATCHING_USER, 400));
}
if (!parsedParams.success) {
return next(new ErrorResponse(errorCode.INVALID_INPUT_REVIEWS_ID, 400));
}
const { id } = parsedId.data;
const { reviewsId } = parsedParams.data;

await errorCheck.reviewsIdExistCheck(reviewsId);
await reviewsService.patchReviews(reviewsId, tokenId);

await reviewsService.patchReviews(reviewsId, id);
return res.status(status.OK).send();
};
54 changes: 54 additions & 0 deletions backend/src/reviews/controller/reviews.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { z } from 'zod';

export const positiveInt = z.coerce.number().int().nonnegative();

export const userSchema = z.object({
id: positiveInt,
});

export const bookInfoIdSchema = positiveInt;
export const reviewsIdSchema = positiveInt;

export const contentSchema = z.string().min(10).max(420);

export type Sort = 'ASC' | 'DESC';
export const sortSchema = z.string().toUpperCase()
.refine((s): s is Sort => s === 'ASC' || s === 'DESC')
.default('DESC' as const);

/** 0: 공개, 1: 비공개, -1: 전체 리뷰 */
type Disabled = 0 | 1 | -1;
const disabledSchema = z.coerce.number().int().refine(
(n): n is Disabled => [-1, 0, 1].includes(n),
(n) => ({ message: `0: 공개, 1: 비공개, -1: 전체 리뷰, 입력값: ${n}` }),
);

export const queryOptionSchema = z.object({
page: positiveInt.default(0),
limit: positiveInt.default(10),
sort: sortSchema,
});

export const getReviewsSchema = z.object({
isMyReview: z.boolean().default(false),
titleOrNickname: z.string().optional(),
disabled: disabledSchema,
}).merge(queryOptionSchema);

export const createReviewsSchema = z.object({
bookInfoId: bookInfoIdSchema,
content: contentSchema,
});

export const updateReviewsSchema = z.object({
reviewsId: reviewsIdSchema,
content: contentSchema,
});

export const deleteReviewsSchema = z.object({
reviewsId: reviewsIdSchema,
});

export const patchReviewsSchema = z.object({
reviewsId: reviewsIdSchema,
});