mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 02:39:03 +00:00
continue extracting user controllers out of routes
This commit is contained in:
@@ -10,6 +10,7 @@ import getBeerRecommendations from '@/services/BeerPost/getBeerRecommendations';
|
||||
import getAllBeerPosts from '@/services/BeerPost/getAllBeerPosts';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import createNewBeerPost from '@/services/BeerPost/createNewBeerPost';
|
||||
import getBeerPostsByPostedById from '@/services/BeerPost/getBeerPostsByPostedById';
|
||||
import {
|
||||
BeerPostRequest,
|
||||
CreateBeerPostRequest,
|
||||
@@ -17,6 +18,7 @@ import {
|
||||
GetAllBeerPostsRequest,
|
||||
GetBeerRecommendationsRequest,
|
||||
} from './types';
|
||||
import { GetPostsByUserIdRequest } from '../types';
|
||||
|
||||
export const checkIfBeerPostOwner = async <BeerPostRequestType extends BeerPostRequest>(
|
||||
req: BeerPostRequestType,
|
||||
@@ -141,3 +143,32 @@ export const createBeerPost = async (
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const getBeerPostsByUserId = async (
|
||||
req: GetPostsByUserIdRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const pageNum = parseInt(req.query.page_num, 10);
|
||||
const pageSize = parseInt(req.query.page_size, 10);
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const beerPosts = await getBeerPostsByPostedById({
|
||||
pageNum,
|
||||
pageSize,
|
||||
postedById: id,
|
||||
});
|
||||
|
||||
const beerPostCount = await DBClient.instance.beerPost.count({
|
||||
where: { postedBy: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', beerPostCount);
|
||||
|
||||
res.status(200).json({
|
||||
message: `Beer posts by user ${id} fetched successfully`,
|
||||
statusCode: 200,
|
||||
payload: beerPosts,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
36
src/controllers/posts/breweries/index.ts
Normal file
36
src/controllers/posts/breweries/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import getAllBreweryPostsByPostedById from '@/services/BreweryPost/getAllBreweryPostsByPostedById';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { z } from 'zod';
|
||||
import { GetPostsByUserIdRequest } from '../types';
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const getBreweryPostsByUserId = async (
|
||||
req: GetPostsByUserIdRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const pageNum = parseInt(req.query.page_num, 10);
|
||||
const pageSize = parseInt(req.query.page_size, 10);
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const breweryPosts = await getAllBreweryPostsByPostedById({
|
||||
pageNum,
|
||||
pageSize,
|
||||
postedById: id,
|
||||
});
|
||||
|
||||
const breweryPostCount = await DBClient.instance.breweryPost.count({
|
||||
where: { postedBy: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', breweryPostCount);
|
||||
|
||||
res.status(200).json({
|
||||
message: `Brewery posts by user ${id} fetched successfully`,
|
||||
statusCode: 200,
|
||||
payload: breweryPosts,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
@@ -3,3 +3,7 @@ import { NextApiRequest } from 'next';
|
||||
export interface GetAllPostsRequest extends NextApiRequest {
|
||||
query: { page_size: string; page_num: string };
|
||||
}
|
||||
|
||||
export interface GetPostsByUserIdRequest extends NextApiRequest {
|
||||
query: { id: string; page_size: string; page_num: string };
|
||||
}
|
||||
|
||||
@@ -19,11 +19,17 @@ import { verifyConfirmationToken } from '@/config/jwt';
|
||||
import updateUserToBeConfirmedById from '@/services/User/updateUserToBeConfirmedById';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import sendResetPasswordEmail from '@/services/User/sendResetPasswordEmail';
|
||||
import { hashPassword } from '@/config/auth/passwordFns';
|
||||
import deleteUserById from '@/services/User/deleteUserById';
|
||||
import {
|
||||
CheckEmailRequest,
|
||||
CheckUsernameRequest,
|
||||
RegisterUserRequest,
|
||||
ResetPasswordRequest,
|
||||
TokenValidationRequest,
|
||||
UpdatePasswordRequest,
|
||||
} from './types';
|
||||
import { EditUserRequest, UserRouteRequest } from '../profile/types';
|
||||
|
||||
export const authenticateUser = expressWrapper(
|
||||
async (
|
||||
@@ -165,3 +171,135 @@ export const resetPassword = async (
|
||||
'If an account with that email exists, we have sent you an email to reset your password.',
|
||||
});
|
||||
};
|
||||
|
||||
export const sendCurrentUser = async (
|
||||
req: UserExtendedNextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) => {
|
||||
const { user } = req;
|
||||
res.status(200).json({
|
||||
message: `Currently logged in as ${user!.username}`,
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
payload: user,
|
||||
});
|
||||
};
|
||||
|
||||
export const checkEmail = async (req: CheckEmailRequest, res: NextApiResponse) => {
|
||||
const { email: emailToCheck } = req.query;
|
||||
|
||||
const email = await findUserByEmail(emailToCheck);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
payload: { emailIsTaken: !!email },
|
||||
statusCode: 200,
|
||||
message: 'Getting email availability.',
|
||||
});
|
||||
};
|
||||
|
||||
export const checkUsername = async (req: CheckUsernameRequest, res: NextApiResponse) => {
|
||||
const { username: usernameToCheck } = req.query;
|
||||
|
||||
const username = await findUserByUsername(usernameToCheck);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
payload: { usernameIsTaken: !!username },
|
||||
statusCode: 200,
|
||||
message: username ? 'Username is taken.' : 'Username is available.',
|
||||
});
|
||||
};
|
||||
|
||||
export const updatePassword = async (
|
||||
req: UpdatePasswordRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { password } = req.body;
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
const user = req.user!;
|
||||
await DBClient.instance.user.update({
|
||||
data: { hash },
|
||||
where: { id: user.id },
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Updated user password.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const resendConfirmation = async (
|
||||
req: UserExtendedNextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) => {
|
||||
const user = req.user!;
|
||||
|
||||
await sendConfirmationEmail(user);
|
||||
res.status(200).json({
|
||||
message: `Resent the confirmation email for ${user.username}.`,
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const editUserInfo = async (
|
||||
req: EditUserRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { email, firstName, lastName, username } = req.body;
|
||||
|
||||
const [usernameIsTaken, emailIsTaken] = await Promise.all([
|
||||
findUserByUsername(username),
|
||||
findUserByEmail(email),
|
||||
]);
|
||||
|
||||
const emailChanged = req.user!.email !== email;
|
||||
const usernameChanged = req.user!.username !== username;
|
||||
|
||||
if (emailIsTaken && emailChanged) {
|
||||
throw new ServerError('Email is already taken', 400);
|
||||
}
|
||||
|
||||
if (usernameIsTaken && usernameChanged) {
|
||||
throw new ServerError('Username is already taken', 400);
|
||||
}
|
||||
|
||||
const updatedUser = await DBClient.instance.user.update({
|
||||
where: { id: req.user!.id },
|
||||
data: {
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
username,
|
||||
accountIsVerified: emailChanged ? false : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'User edited successfully',
|
||||
payload: updatedUser,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteAccount = async (
|
||||
req: UserRouteRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
const deletedUser = await deleteUserById(id);
|
||||
|
||||
if (!deletedUser) {
|
||||
throw new ServerError('Could not find a user with that id.', 400);
|
||||
}
|
||||
|
||||
res.send({
|
||||
message: 'Successfully deleted user.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
@@ -1,5 +1,8 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import { CreateUserValidationSchema } from '@/services/User/schema/CreateUserValidationSchemas';
|
||||
import {
|
||||
CreateUserValidationSchema,
|
||||
UpdatePasswordSchema,
|
||||
} from '@/services/User/schema/CreateUserValidationSchemas';
|
||||
import TokenValidationSchema from '@/services/User/schema/TokenValidationSchema';
|
||||
import { NextApiRequest } from 'next';
|
||||
import { z } from 'zod';
|
||||
@@ -15,3 +18,14 @@ export interface TokenValidationRequest extends UserExtendedNextApiRequest {
|
||||
export interface ResetPasswordRequest extends NextApiRequest {
|
||||
body: { email: string };
|
||||
}
|
||||
|
||||
export interface UpdatePasswordRequest extends UserExtendedNextApiRequest {
|
||||
body: z.infer<typeof UpdatePasswordSchema>;
|
||||
}
|
||||
export interface CheckEmailRequest extends NextApiRequest {
|
||||
query: { email: string };
|
||||
}
|
||||
|
||||
export interface CheckUsernameRequest extends NextApiRequest {
|
||||
query: { username: string };
|
||||
}
|
||||
237
src/controllers/users/profile/index.ts
Normal file
237
src/controllers/users/profile/index.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { z } from 'zod';
|
||||
import getUsersFollowingUser from '@/services/UserFollows/getUsersFollowingUser';
|
||||
import getUsersFollowedByUser from '@/services/UserFollows/getUsersFollowedByUser';
|
||||
import { NextHandler } from 'next-connect';
|
||||
import updateUserAvatarById, {
|
||||
UpdateUserAvatarByIdParams,
|
||||
} from '@/services/UserAccount/UpdateUserAvatarByIdParams';
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import updateUserProfileById from '@/services/User/updateUserProfileById';
|
||||
import {
|
||||
UserRouteRequest,
|
||||
GetUserFollowInfoRequest,
|
||||
EditUserRequest,
|
||||
UpdateAvatarRequest,
|
||||
UpdateProfileRequest,
|
||||
} from './types';
|
||||
|
||||
export const followUser = async (
|
||||
req: UserRouteRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const currentUser = req.user!;
|
||||
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
|
||||
where: {
|
||||
followerId: currentUser.id,
|
||||
followingId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!userIsFollowedBySessionUser) {
|
||||
await DBClient.instance.userFollow.create({
|
||||
data: { followerId: currentUser.id, followingId: id },
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
message: 'Now following user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await DBClient.instance.userFollow.delete({
|
||||
where: {
|
||||
followerId_followingId: {
|
||||
followerId: currentUser.id,
|
||||
followingId: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
message: 'No longer following user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUserFollowers = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { id, page_num, page_size } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const pageNum = parseInt(page_num, 10);
|
||||
const pageSize = parseInt(page_size, 10);
|
||||
|
||||
const following = await getUsersFollowingUser({
|
||||
userId: id,
|
||||
pageNum,
|
||||
pageSize,
|
||||
});
|
||||
const followingCount = await DBClient.instance.userFollow.count({
|
||||
where: { following: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', followingCount);
|
||||
|
||||
res.json({
|
||||
message: 'Retrieved users that are followed by queried user',
|
||||
payload: following,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
export const getUsersFollowed = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { id, page_num, page_size } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const pageNum = parseInt(page_num, 10);
|
||||
const pageSize = parseInt(page_size, 10);
|
||||
|
||||
const following = await getUsersFollowedByUser({
|
||||
userId: id,
|
||||
pageNum,
|
||||
pageSize,
|
||||
});
|
||||
const followingCount = await DBClient.instance.userFollow.count({
|
||||
where: { follower: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', followingCount);
|
||||
|
||||
res.json({
|
||||
message: 'Retrieved users that are followed by queried user',
|
||||
payload: following,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
export const checkIfUserIsFollowedBySessionUser = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const currentUser = req.user!;
|
||||
|
||||
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
|
||||
where: { followerId: currentUser.id, followingId: id },
|
||||
});
|
||||
|
||||
if (!userIsFollowedBySessionUser) {
|
||||
res.status(200).json({
|
||||
message: 'User is not followed by the current user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
payload: { isFollowed: false },
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
message: 'User is followed by the current user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
payload: { isFollowed: true },
|
||||
});
|
||||
};
|
||||
|
||||
export const checkIfUserCanEditUser = async (
|
||||
req: EditUserRequest,
|
||||
res: NextApiResponse,
|
||||
next: NextHandler,
|
||||
) => {
|
||||
const authenticatedUser = req.user!;
|
||||
|
||||
const userToUpdate = await findUserById(req.query.id);
|
||||
if (!userToUpdate) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
if (authenticatedUser.id !== userToUpdate.id) {
|
||||
throw new ServerError('You are not permitted to modify this user', 403);
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
export const checkIfUserCanUpdateProfile = async <T extends UserExtendedNextApiRequest>(
|
||||
req: T,
|
||||
res: NextApiResponse,
|
||||
next: NextHandler,
|
||||
) => {
|
||||
const user = req.user!;
|
||||
|
||||
if (user.id !== req.query.id) {
|
||||
throw new ServerError('You can only update your own profile.', 403);
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
|
||||
export const updateAvatar = async (req: UpdateAvatarRequest, res: NextApiResponse) => {
|
||||
const { file, user } = req;
|
||||
|
||||
const avatar: UpdateUserAvatarByIdParams['data']['avatar'] = {
|
||||
alt: file.originalname,
|
||||
path: file.path,
|
||||
caption: '',
|
||||
};
|
||||
|
||||
await updateUserAvatarById({ id: user!.id, data: { avatar } });
|
||||
res.status(200).json({
|
||||
message: 'User avatar updated successfully.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const updateProfile = async (req: UpdateProfileRequest, res: NextApiResponse) => {
|
||||
const user = req.user!;
|
||||
const { body } = req;
|
||||
|
||||
await updateUserProfileById({ id: user!.id, data: { bio: body.bio } });
|
||||
|
||||
res.status(200).json({
|
||||
message: 'Profile updated successfully.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
23
src/controllers/users/profile/types/index.ts
Normal file
23
src/controllers/users/profile/types/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import EditUserSchema from '@/services/User/schema/EditUserSchema';
|
||||
import { z } from 'zod';
|
||||
|
||||
export interface UserRouteRequest extends UserExtendedNextApiRequest {
|
||||
query: { id: string };
|
||||
}
|
||||
|
||||
export interface GetUserFollowInfoRequest extends UserExtendedNextApiRequest {
|
||||
query: { id: string; page_size: string; page_num: string };
|
||||
}
|
||||
|
||||
export interface EditUserRequest extends UserRouteRequest {
|
||||
body: z.infer<typeof EditUserSchema>;
|
||||
}
|
||||
|
||||
export interface UpdateAvatarRequest extends UserExtendedNextApiRequest {
|
||||
file: Express.Multer.File;
|
||||
}
|
||||
|
||||
export interface UpdateProfileRequest extends UserExtendedNextApiRequest {
|
||||
body: { bio: string };
|
||||
}
|
||||
@@ -2,9 +2,7 @@ import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
import { followUser } from '@/controllers/users/profile';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
@@ -21,55 +19,6 @@ const router = createRouter<
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const followUser = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const currentUser = req.user!;
|
||||
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
|
||||
where: {
|
||||
followerId: currentUser.id,
|
||||
followingId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!userIsFollowedBySessionUser) {
|
||||
await DBClient.instance.userFollow.create({
|
||||
data: { followerId: currentUser.id, followingId: id },
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
message: 'Now following user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await DBClient.instance.userFollow.delete({
|
||||
where: {
|
||||
followerId_followingId: {
|
||||
followerId: currentUser.id,
|
||||
followingId: id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
message: 'No longer following user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
router.post(
|
||||
validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }),
|
||||
getCurrentUser,
|
||||
|
||||
@@ -1,59 +1,18 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
import getUsersFollowingUser from '@/services/UserFollows/getUsersFollowingUser';
|
||||
import { getUserFollowers } from '@/controllers/users/profile';
|
||||
import { GetUserFollowInfoRequest } from '@/controllers/users/profile/types';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface GetUserFollowInfoRequest extends UserExtendedNextApiRequest {
|
||||
query: { id: string; page_size: string; page_num: string };
|
||||
}
|
||||
|
||||
const router = createRouter<
|
||||
GetUserFollowInfoRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const getFollowingInfo = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { id, page_num, page_size } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const pageNum = parseInt(page_num, 10);
|
||||
const pageSize = parseInt(page_size, 10);
|
||||
|
||||
const following = await getUsersFollowingUser({
|
||||
userId: id,
|
||||
pageNum,
|
||||
pageSize,
|
||||
});
|
||||
const followingCount = await DBClient.instance.userFollow.count({
|
||||
where: { following: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', followingCount);
|
||||
|
||||
res.json({
|
||||
message: 'Retrieved users that are followed by queried user',
|
||||
payload: following,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
validateRequest({
|
||||
querySchema: z.object({
|
||||
@@ -62,7 +21,7 @@ router.get(
|
||||
page_num: z.string().regex(/^\d+$/),
|
||||
}),
|
||||
}),
|
||||
getFollowingInfo,
|
||||
getUserFollowers,
|
||||
);
|
||||
|
||||
const handler = router.handler(NextConnectOptions);
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
import getUsersFollowedByUser from '@/services/UserFollows/getUsersFollowedByUser';
|
||||
import { getUsersFollowed } from '@/controllers/users/profile';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
import { NextApiResponse } from 'next';
|
||||
@@ -20,40 +17,6 @@ const router = createRouter<
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const getFollowingInfo = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { id, page_num, page_size } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const pageNum = parseInt(page_num, 10);
|
||||
const pageSize = parseInt(page_size, 10);
|
||||
|
||||
const following = await getUsersFollowedByUser({
|
||||
userId: id,
|
||||
pageNum,
|
||||
pageSize,
|
||||
});
|
||||
const followingCount = await DBClient.instance.userFollow.count({
|
||||
where: { follower: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', followingCount);
|
||||
|
||||
res.json({
|
||||
message: 'Retrieved users that are followed by queried user',
|
||||
payload: following,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
validateRequest({
|
||||
querySchema: z.object({
|
||||
@@ -62,7 +25,7 @@ router.get(
|
||||
page_num: z.string().regex(/^\d+$/),
|
||||
}),
|
||||
}),
|
||||
getFollowingInfo,
|
||||
getUsersFollowed,
|
||||
);
|
||||
|
||||
const handler = router.handler(NextConnectOptions);
|
||||
|
||||
@@ -1,113 +1,16 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import deleteUserById from '@/services/User/deleteUserById';
|
||||
import findUserByEmail from '@/services/User/findUserByEmail';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
import findUserByUsername from '@/services/User/findUserByUsername';
|
||||
import { BaseCreateUserSchema } from '@/services/User/schema/CreateUserValidationSchemas';
|
||||
import { editUserInfo, deleteAccount } from '@/controllers/users/auth';
|
||||
import { checkIfUserCanEditUser } from '@/controllers/users/profile';
|
||||
import { EditUserRequest } from '@/controllers/users/profile/types';
|
||||
import EditUserSchema from '@/services/User/schema/EditUserSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
import { NextApiResponse } from 'next';
|
||||
import { NextHandler, createRouter } from 'next-connect';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
const EditUserSchema = BaseCreateUserSchema.pick({
|
||||
username: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
});
|
||||
|
||||
interface UserRouteRequest extends UserExtendedNextApiRequest {
|
||||
query: { id: string };
|
||||
}
|
||||
|
||||
interface EditUserRequest extends UserRouteRequest {
|
||||
body: z.infer<typeof EditUserSchema>;
|
||||
}
|
||||
|
||||
const checkIfUserCanEditUser = async (
|
||||
req: EditUserRequest,
|
||||
res: NextApiResponse,
|
||||
next: NextHandler,
|
||||
) => {
|
||||
const authenticatedUser = req.user!;
|
||||
|
||||
const userToUpdate = await findUserById(req.query.id);
|
||||
if (!userToUpdate) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
if (authenticatedUser.id !== userToUpdate.id) {
|
||||
throw new ServerError('You are not permitted to modify this user', 403);
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
const editUser = async (
|
||||
req: EditUserRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { email, firstName, lastName, username } = req.body;
|
||||
|
||||
const [usernameIsTaken, emailIsTaken] = await Promise.all([
|
||||
findUserByUsername(username),
|
||||
findUserByEmail(email),
|
||||
]);
|
||||
|
||||
const emailChanged = req.user!.email !== email;
|
||||
const usernameChanged = req.user!.username !== username;
|
||||
|
||||
if (emailIsTaken && emailChanged) {
|
||||
throw new ServerError('Email is already taken', 400);
|
||||
}
|
||||
|
||||
if (usernameIsTaken && usernameChanged) {
|
||||
throw new ServerError('Username is already taken', 400);
|
||||
}
|
||||
|
||||
const updatedUser = await DBClient.instance.user.update({
|
||||
where: { id: req.user!.id },
|
||||
data: {
|
||||
email,
|
||||
firstName,
|
||||
lastName,
|
||||
username,
|
||||
accountIsVerified: emailChanged ? false : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'User edited successfully',
|
||||
payload: updatedUser,
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
});
|
||||
};
|
||||
|
||||
const deleteUser = async (
|
||||
req: UserRouteRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
const deletedUser = await deleteUserById(id);
|
||||
|
||||
if (!deletedUser) {
|
||||
throw new ServerError('Could not find a user with that id.', 400);
|
||||
}
|
||||
|
||||
res.send({
|
||||
message: 'Successfully deleted user.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
const router = createRouter<
|
||||
EditUserRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
@@ -120,7 +23,7 @@ router.put(
|
||||
querySchema: z.object({ id: z.string().cuid() }),
|
||||
}),
|
||||
checkIfUserCanEditUser,
|
||||
editUser,
|
||||
editUserInfo,
|
||||
);
|
||||
|
||||
router.delete(
|
||||
@@ -129,7 +32,7 @@ router.delete(
|
||||
querySchema: z.object({ id: z.string().cuid() }),
|
||||
}),
|
||||
checkIfUserCanEditUser,
|
||||
deleteUser,
|
||||
deleteAccount,
|
||||
);
|
||||
|
||||
const handler = router.handler(NextConnectOptions);
|
||||
|
||||
@@ -1,62 +1,21 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import findUserById from '@/services/User/findUserById';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface GetUserFollowInfoRequest extends UserExtendedNextApiRequest {
|
||||
query: { id: string };
|
||||
}
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
|
||||
import { checkIfUserIsFollowedBySessionUser } from '@/controllers/users/profile';
|
||||
import { GetUserFollowInfoRequest } from '@/controllers/users/profile/types';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
const router = createRouter<
|
||||
GetUserFollowInfoRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const checkIfUserIsFollowedBySessionUser = async (
|
||||
req: GetUserFollowInfoRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { id } = req.query;
|
||||
|
||||
const user = await findUserById(id);
|
||||
if (!user) {
|
||||
throw new ServerError('User not found', 404);
|
||||
}
|
||||
|
||||
const currentUser = req.user!;
|
||||
|
||||
const userIsFollowedBySessionUser = await DBClient.instance.userFollow.findFirst({
|
||||
where: { followerId: currentUser.id, followingId: id },
|
||||
});
|
||||
|
||||
if (!userIsFollowedBySessionUser) {
|
||||
res.status(200).json({
|
||||
message: 'User is not followed by the current user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
payload: { isFollowed: false },
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
message: 'User is followed by the current user.',
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
payload: { isFollowed: true },
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
validateRequest({ querySchema: z.object({ id: z.string().cuid() }) }),
|
||||
getCurrentUser,
|
||||
|
||||
@@ -1,48 +1,15 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import getBeerPostsByPostedById from '@/services/BeerPost/getBeerPostsByPostedById';
|
||||
import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
interface GetBeerPostsRequest extends NextApiRequest {
|
||||
query: {
|
||||
page_num: string;
|
||||
page_size: string;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
const getBeerPostsByUserId = async (
|
||||
req: GetBeerPostsRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const pageNum = parseInt(req.query.page_num, 10);
|
||||
const pageSize = parseInt(req.query.page_size, 10);
|
||||
|
||||
const { id } = req.query;
|
||||
|
||||
const beerPosts = await getBeerPostsByPostedById({ pageNum, pageSize, postedById: id });
|
||||
|
||||
const beerPostCount = await DBClient.instance.beerPost.count({
|
||||
where: { postedBy: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', beerPostCount);
|
||||
|
||||
res.status(200).json({
|
||||
message: `Beer posts by user ${id} fetched successfully`,
|
||||
statusCode: 200,
|
||||
payload: beerPosts,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
import { GetPostsByUserIdRequest } from '@/controllers/posts/types';
|
||||
import { getBeerPostsByUserId } from '@/controllers/posts/beerPosts';
|
||||
|
||||
const router = createRouter<
|
||||
GetBeerPostsRequest,
|
||||
GetPostsByUserIdRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
|
||||
@@ -1,52 +1,15 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import getAllBreweryPostsByPostedById from '@/services/BreweryPost/getAllBreweryPostsByPostedById';
|
||||
import PaginatedQueryResponseSchema from '@/services/schema/PaginatedQueryResponseSchema';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
|
||||
interface GetBreweryPostsRequest extends NextApiRequest {
|
||||
query: {
|
||||
page_num: string;
|
||||
page_size: string;
|
||||
id: string;
|
||||
};
|
||||
}
|
||||
|
||||
const getBreweryPostsByUserId = 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 { id } = req.query;
|
||||
|
||||
const breweryPosts = await getAllBreweryPostsByPostedById({
|
||||
pageNum,
|
||||
pageSize,
|
||||
postedById: id,
|
||||
});
|
||||
|
||||
const breweryPostCount = await DBClient.instance.breweryPost.count({
|
||||
where: { postedBy: { id } },
|
||||
});
|
||||
|
||||
res.setHeader('X-Total-Count', breweryPostCount);
|
||||
|
||||
res.status(200).json({
|
||||
message: `Brewery posts by user ${id} fetched successfully`,
|
||||
statusCode: 200,
|
||||
payload: breweryPosts,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
import { getBreweryPostsByUserId } from '@/controllers/posts/breweries';
|
||||
import { GetPostsByUserIdRequest } from '@/controllers/posts/types';
|
||||
|
||||
const router = createRouter<
|
||||
GetBreweryPostsRequest,
|
||||
GetPostsByUserIdRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const checkIfUserCanUpdateProfile = async (
|
||||
await next();
|
||||
};
|
||||
|
||||
const updateProfile = async (req: UpdateProfileRequest, res: NextApiResponse) => {
|
||||
const updateAvatar = async (req: UpdateProfileRequest, res: NextApiResponse) => {
|
||||
const { file, user } = req;
|
||||
|
||||
const avatar: UpdateUserAvatarByIdParams['data']['avatar'] = {
|
||||
@@ -60,7 +60,7 @@ router.put(
|
||||
checkIfUserCanUpdateProfile,
|
||||
// @ts-expect-error
|
||||
singleUploadMiddleware,
|
||||
updateProfile,
|
||||
updateAvatar,
|
||||
);
|
||||
|
||||
const handler = router.handler();
|
||||
|
||||
@@ -1,75 +1,13 @@
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import ServerError from '@/config/util/ServerError';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import GetUserSchema from '@/services/User/schema/GetUserSchema';
|
||||
import { checkIfUserCanUpdateProfile, updateProfile } from '@/controllers/users/profile';
|
||||
import { UpdateProfileRequest } from '@/controllers/users/profile/types';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { NextHandler, createRouter } from 'next-connect';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface UpdateProfileRequest extends UserExtendedNextApiRequest {
|
||||
body: { bio: string };
|
||||
}
|
||||
|
||||
interface UpdateUserProfileByIdParams {
|
||||
id: string;
|
||||
data: { bio: string };
|
||||
}
|
||||
|
||||
const updateUserProfileById = async ({ id, data }: UpdateUserProfileByIdParams) => {
|
||||
const user: z.infer<typeof GetUserSchema> = await DBClient.instance.user.update({
|
||||
where: { id },
|
||||
data: { bio: data.bio },
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
bio: true,
|
||||
userAvatar: true,
|
||||
accountIsVerified: true,
|
||||
createdAt: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
updatedAt: true,
|
||||
dateOfBirth: true,
|
||||
role: true,
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
const updateProfile = async (req: UpdateProfileRequest, res: NextApiResponse) => {
|
||||
const user = req.user!;
|
||||
const { body } = req;
|
||||
|
||||
await updateUserProfileById({ id: user!.id, data: { bio: body.bio } });
|
||||
|
||||
res.status(200).json({
|
||||
message: 'Profile updated successfully.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
|
||||
const checkIfUserCanUpdateProfile = async (
|
||||
req: UpdateProfileRequest,
|
||||
res: NextApiResponse,
|
||||
next: NextHandler,
|
||||
) => {
|
||||
const user = req.user!;
|
||||
|
||||
if (user.id !== req.query.id) {
|
||||
throw new ServerError('You can only update your own profile.', 403);
|
||||
}
|
||||
|
||||
await next();
|
||||
};
|
||||
|
||||
const router = createRouter<
|
||||
UpdateProfileRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
|
||||
@@ -1,38 +1,18 @@
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import findUserByEmail from '@/services/User/findUserByEmail';
|
||||
|
||||
const CheckEmailRequestQuerySchema = z.object({
|
||||
email: z.string(),
|
||||
});
|
||||
|
||||
interface CheckEmailRequestSchema extends NextApiRequest {
|
||||
query: z.infer<typeof CheckEmailRequestQuerySchema>;
|
||||
}
|
||||
import { CheckEmailRequest } from '@/controllers/users/auth/types';
|
||||
import { checkEmail } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
CheckEmailRequestSchema,
|
||||
CheckEmailRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const checkEmail = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { email: emailToCheck } = req.query;
|
||||
|
||||
const email = await findUserByEmail(emailToCheck as string);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
payload: { emailIsTaken: !!email },
|
||||
statusCode: 200,
|
||||
message: 'Getting email availability.',
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
validateRequest({ querySchema: z.object({ email: z.string().email() }) }),
|
||||
checkEmail,
|
||||
|
||||
@@ -1,38 +1,19 @@
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import findUserByUsername from '@/services/User/findUserByUsername';
|
||||
|
||||
const CheckUsernameRequestQuerySchema = z.object({
|
||||
username: z.string(),
|
||||
});
|
||||
|
||||
interface CheckUsernameRequestSchema extends NextApiRequest {
|
||||
query: z.infer<typeof CheckUsernameRequestQuerySchema>;
|
||||
}
|
||||
import { CheckUsernameRequest } from '@/controllers/users/auth/types';
|
||||
import { checkUsername } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
CheckUsernameRequestSchema,
|
||||
CheckUsernameRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
>();
|
||||
|
||||
const checkUsername = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const { username: usernameToCheck } = req.query;
|
||||
|
||||
const user = await findUserByUsername(usernameToCheck as string);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
payload: { usernameIsTaken: !!user },
|
||||
statusCode: 200,
|
||||
message: 'Getting username availability.',
|
||||
});
|
||||
};
|
||||
|
||||
router.get(
|
||||
validateRequest({ querySchema: z.object({ username: z.string() }) }),
|
||||
checkUsername,
|
||||
|
||||
@@ -7,8 +7,8 @@ import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
|
||||
import { TokenValidationRequest } from '@/controllers/auth/types';
|
||||
import { confirmUser } from '@/controllers/auth';
|
||||
import { TokenValidationRequest } from '@/controllers/users/auth/types';
|
||||
import { confirmUser } from '@/controllers/users/auth';
|
||||
import TokenValidationSchema from '@/services/User/schema/TokenValidationSchema';
|
||||
|
||||
const router = createRouter<
|
||||
|
||||
@@ -5,16 +5,7 @@ import { NextApiResponse } from 'next';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
const sendCurrentUser = async (req: UserExtendedNextApiRequest, res: NextApiResponse) => {
|
||||
const { user } = req;
|
||||
res.status(200).json({
|
||||
message: `Currently logged in as ${user!.username}`,
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
payload: user,
|
||||
});
|
||||
};
|
||||
import { sendCurrentUser } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
UserExtendedNextApiRequest,
|
||||
|
||||
@@ -1,38 +1,14 @@
|
||||
import { hashPassword } from '@/config/auth/passwordFns';
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import { updatePassword } from '@/controllers/users/auth';
|
||||
import { UpdatePasswordRequest } from '@/controllers/users/auth/types';
|
||||
import { UpdatePasswordSchema } from '@/services/User/schema/CreateUserValidationSchemas';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
interface UpdatePasswordRequest extends UserExtendedNextApiRequest {
|
||||
body: z.infer<typeof UpdatePasswordSchema>;
|
||||
}
|
||||
|
||||
const updatePassword = async (
|
||||
req: UpdatePasswordRequest,
|
||||
res: NextApiResponse<z.infer<typeof APIResponseValidationSchema>>,
|
||||
) => {
|
||||
const { password } = req.body;
|
||||
const hash = await hashPassword(password);
|
||||
|
||||
const user = req.user!;
|
||||
await DBClient.instance.user.update({
|
||||
data: { hash },
|
||||
where: { id: user.id },
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Updated user password.',
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
const router = createRouter<
|
||||
UpdatePasswordRequest,
|
||||
NextApiResponse<z.infer<typeof APIResponseValidationSchema>>
|
||||
|
||||
@@ -5,8 +5,8 @@ import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import { resetPassword } from '@/controllers/auth';
|
||||
import { ResetPasswordRequest } from '@/controllers/auth/types';
|
||||
import { resetPassword } from '@/controllers/users/auth';
|
||||
import { ResetPasswordRequest } from '@/controllers/users/auth/types';
|
||||
|
||||
const router = createRouter<
|
||||
ResetPasswordRequest,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { z } from 'zod';
|
||||
import LoginValidationSchema from '@/services/User/schema/LoginValidationSchema';
|
||||
import { UserExtendedNextApiRequest } from '@/config/auth/types';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import { authenticateUser, loginUser } from '@/controllers/auth';
|
||||
import { authenticateUser, loginUser } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
UserExtendedNextApiRequest,
|
||||
|
||||
@@ -3,7 +3,7 @@ import APIResponseValidationSchema from '@/validation/APIResponseValidationSchem
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
import { logoutUser } from '@/controllers/auth';
|
||||
import { logoutUser } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
NextApiRequest,
|
||||
|
||||
@@ -5,8 +5,8 @@ import { CreateUserValidationSchema } from '@/services/User/schema/CreateUserVal
|
||||
import NextConnectOptions from '@/config/nextConnect/NextConnectOptions';
|
||||
import validateRequest from '@/config/nextConnect/middleware/validateRequest';
|
||||
import APIResponseValidationSchema from '@/validation/APIResponseValidationSchema';
|
||||
import { registerUser } from '@/controllers/auth';
|
||||
import { RegisterUserRequest } from '@/controllers/auth/types';
|
||||
import { registerUser } from '@/controllers/users/auth';
|
||||
import { RegisterUserRequest } from '@/controllers/users/auth/types';
|
||||
|
||||
const router = createRouter<
|
||||
RegisterUserRequest,
|
||||
|
||||
@@ -5,21 +5,7 @@ import { NextApiResponse } from 'next';
|
||||
import getCurrentUser from '@/config/nextConnect/middleware/getCurrentUser';
|
||||
import { createRouter } from 'next-connect';
|
||||
import { z } from 'zod';
|
||||
import sendConfirmationEmail from '@/services/User/sendConfirmationEmail';
|
||||
|
||||
const resendConfirmation = async (
|
||||
req: UserExtendedNextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) => {
|
||||
const user = req.user!;
|
||||
|
||||
await sendConfirmationEmail(user);
|
||||
res.status(200).json({
|
||||
message: `Resent the confirmation email for ${user.username}.`,
|
||||
statusCode: 200,
|
||||
success: true,
|
||||
});
|
||||
};
|
||||
import { resendConfirmation } from '@/controllers/users/auth';
|
||||
|
||||
const router = createRouter<
|
||||
UserExtendedNextApiRequest,
|
||||
|
||||
@@ -16,7 +16,7 @@ const getBeerPostsByBeerStyleId = async ({
|
||||
const beers = await DBClient.instance.beerPost.findMany({
|
||||
where: { styleId },
|
||||
take: pageSize,
|
||||
skip: pageNum * pageSize,
|
||||
skip: (pageNum - 1) * pageSize,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
|
||||
@@ -16,7 +16,7 @@ const getAllBeerPostsByBreweryId = async ({
|
||||
const beers = await DBClient.instance.beerPost.findMany({
|
||||
where: { breweryId },
|
||||
take: pageSize,
|
||||
skip: pageNum * pageSize,
|
||||
skip: (pageNum - 1) * pageSize,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
|
||||
@@ -16,7 +16,7 @@ const getBeerPostsByPostedById = async ({
|
||||
const beers = await DBClient.instance.beerPost.findMany({
|
||||
where: { postedBy: { id: postedById } },
|
||||
take: pageSize,
|
||||
skip: pageNum * pageSize,
|
||||
skip: (pageNum - 1) * pageSize,
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
|
||||
10
src/services/User/schema/EditUserSchema.ts
Normal file
10
src/services/User/schema/EditUserSchema.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { BaseCreateUserSchema } from './CreateUserValidationSchemas';
|
||||
|
||||
const EditUserSchema = BaseCreateUserSchema.pick({
|
||||
username: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
});
|
||||
|
||||
export default EditUserSchema;
|
||||
33
src/services/User/updateUserProfileById.ts
Normal file
33
src/services/User/updateUserProfileById.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import DBClient from '@/prisma/DBClient';
|
||||
import { z } from 'zod';
|
||||
import GetUserSchema from './schema/GetUserSchema';
|
||||
|
||||
interface UpdateUserProfileByIdParams {
|
||||
id: string;
|
||||
data: { bio: string };
|
||||
}
|
||||
|
||||
const updateUserProfileById = async ({ id, data }: UpdateUserProfileByIdParams) => {
|
||||
const user: z.infer<typeof GetUserSchema> = await DBClient.instance.user.update({
|
||||
where: { id },
|
||||
data: { bio: data.bio },
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
bio: true,
|
||||
userAvatar: true,
|
||||
accountIsVerified: true,
|
||||
createdAt: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
updatedAt: true,
|
||||
dateOfBirth: true,
|
||||
role: true,
|
||||
},
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export default updateUserProfileById;
|
||||
Reference in New Issue
Block a user