mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
Add user routes
This commit is contained in:
@@ -2,8 +2,13 @@ import { Request, Response } from 'express';
|
|||||||
import { ApiSuccess, getSuccessResponse } from '@/utils';
|
import { ApiSuccess, getSuccessResponse } from '@/utils';
|
||||||
import { toApiModel } from '@helpers/api-model';
|
import { toApiModel } from '@helpers/api-model';
|
||||||
import { service } from '@services/index';
|
import { service } from '@services/index';
|
||||||
|
import { validation } from '@validations/index';
|
||||||
|
import { TypedRequest } from '@validations/shared.validation';
|
||||||
|
|
||||||
const getUserDetail = async (req: Request, res: Response) => {
|
const getUserDetail = async (
|
||||||
|
req: TypedRequest<typeof validation.users.detail>,
|
||||||
|
res: Response
|
||||||
|
) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const user = await service.users.findById(req.authUser, { id });
|
const user = await service.users.findById(req.authUser, { id });
|
||||||
const success = ApiSuccess.ok({ data: toApiModel.users([user])[0] });
|
const success = ApiSuccess.ok({ data: toApiModel.users([user])[0] });
|
||||||
@@ -16,7 +21,39 @@ const getUserList = async (_req: Request, res: Response) => {
|
|||||||
return res.status(success.statusCode).json(getSuccessResponse(success));
|
return res.status(success.statusCode).json(getSuccessResponse(success));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createUser = async (
|
||||||
|
req: TypedRequest<typeof validation.users.createUser>,
|
||||||
|
res: Response
|
||||||
|
) => {
|
||||||
|
const user = await service.users.createUser(req.body);
|
||||||
|
const success = ApiSuccess.ok({ data: toApiModel.users([user])[0] });
|
||||||
|
return res.status(success.statusCode).json(getSuccessResponse(success));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUser = async (
|
||||||
|
req: TypedRequest<typeof validation.users.updateUser>,
|
||||||
|
res: Response
|
||||||
|
) => {
|
||||||
|
const { userId } = req.params;
|
||||||
|
const user = await service.users.updateUser({ userId }, req.body);
|
||||||
|
const success = ApiSuccess.ok({ data: toApiModel.users([user])[0] });
|
||||||
|
return res.status(success.statusCode).json(getSuccessResponse(success));
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteUser = async (
|
||||||
|
req: TypedRequest<typeof validation.users.deleteUser>,
|
||||||
|
res: Response
|
||||||
|
) => {
|
||||||
|
const { userId } = req.params;
|
||||||
|
await service.users.deleteUser({ userId });
|
||||||
|
const success = ApiSuccess.noContent({ data: null });
|
||||||
|
return res.status(success.statusCode).json(getSuccessResponse(success));
|
||||||
|
};
|
||||||
|
|
||||||
export const usersController = {
|
export const usersController = {
|
||||||
|
createUser,
|
||||||
|
deleteUser,
|
||||||
getUserDetail,
|
getUserDetail,
|
||||||
getUserList,
|
getUserList,
|
||||||
|
updateUser,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -598,6 +598,7 @@ const users = (
|
|||||||
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
||||||
id: item.id,
|
id: item.id,
|
||||||
username: item.username,
|
username: item.username,
|
||||||
|
displayName: item.displayName,
|
||||||
accessToken: item.accessToken,
|
accessToken: item.accessToken,
|
||||||
refreshToken: item.refreshToken,
|
refreshToken: item.refreshToken,
|
||||||
enabled: item.enabled,
|
enabled: item.enabled,
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
import express, { Router } from 'express';
|
import express, { Router } from 'express';
|
||||||
import { controller } from '@controllers/index';
|
import { controller } from '@controllers/index';
|
||||||
import { validateRequest, validation } from '@validations/index';
|
import { service } from '@services/index';
|
||||||
|
import { ApiError } from '@utils/index';
|
||||||
import { authenticateAdmin } from '../middleware/authenticate-admin';
|
import { authenticateAdmin } from '../middleware/authenticate-admin';
|
||||||
|
|
||||||
export const router: Router = express.Router({ mergeParams: true });
|
export const router: Router = express.Router({ mergeParams: true });
|
||||||
|
|
||||||
router.get('/', authenticateAdmin, controller.users.getUserList);
|
router
|
||||||
|
.route('/')
|
||||||
|
.get(authenticateAdmin, controller.users.getUserList)
|
||||||
|
.post(authenticateAdmin, controller.users.createUser);
|
||||||
|
|
||||||
router.get(
|
router.param('userId', async (req, _res, next, userId) => {
|
||||||
':serverId',
|
await service.users.findById(req.authUser, { id: userId });
|
||||||
validateRequest(validation.users.detail),
|
|
||||||
controller.users.getUserDetail
|
if (req.authUser.isAdmin || req.authUser.id === userId) {
|
||||||
);
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ApiError.forbidden('You are not allowed to access this resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
router.route('/:userId/update').post(controller.users.updateUser);
|
||||||
|
|
||||||
|
router.route('/:userId/delete').post(controller.users.deleteUser);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { prisma } from '../lib';
|
import bcrypt from 'bcryptjs';
|
||||||
import { AuthUser } from '../middleware';
|
import { prisma } from '@lib/prisma';
|
||||||
import { ApiError } from '../utils';
|
import { AuthUser } from '@middleware/authenticate';
|
||||||
|
import { randomString, ApiError } from '@utils/index';
|
||||||
|
|
||||||
const findById = async (user: AuthUser, options: { id: string }) => {
|
const findById = async (user: AuthUser, options: { id: string }) => {
|
||||||
const { id } = options;
|
const { id } = options;
|
||||||
@@ -26,7 +27,71 @@ const findMany = async () => {
|
|||||||
return users;
|
return users;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createUser = async (options: {
|
||||||
|
displayName?: string;
|
||||||
|
password: string;
|
||||||
|
username: string;
|
||||||
|
}) => {
|
||||||
|
const { password, username, displayName } = options;
|
||||||
|
|
||||||
|
const [userExists, displayNameExists] = await prisma.$transaction([
|
||||||
|
prisma.user.findUnique({ where: { username } }),
|
||||||
|
prisma.user.findUnique({ where: { displayName } }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (userExists) {
|
||||||
|
throw ApiError.conflict('The user already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayNameExists) {
|
||||||
|
throw ApiError.conflict('The display name already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashedPassword = await bcrypt.hash(password, 12);
|
||||||
|
|
||||||
|
const user = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
deviceId: `${username}_${randomString(10)}`,
|
||||||
|
enabled: false,
|
||||||
|
password: hashedPassword,
|
||||||
|
username,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteUser = async (options: { userId: string }) => {
|
||||||
|
const { userId } = options;
|
||||||
|
|
||||||
|
const user = await prisma.user.delete({ where: { id: userId } });
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUser = async (
|
||||||
|
options: { userId: string },
|
||||||
|
data: {
|
||||||
|
password?: string;
|
||||||
|
username?: string;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const { userId } = options;
|
||||||
|
const { username, password } = data;
|
||||||
|
|
||||||
|
const hashedPassword = password && (await bcrypt.hash(password, 12));
|
||||||
|
|
||||||
|
const user = await prisma.user.update({
|
||||||
|
data: { password: hashedPassword, username },
|
||||||
|
where: { id: userId },
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
|
||||||
export const usersService = {
|
export const usersService = {
|
||||||
|
createUser,
|
||||||
|
deleteUser,
|
||||||
findById,
|
findById,
|
||||||
findMany,
|
findMany,
|
||||||
|
updateUser,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const login = {
|
|||||||
const register = {
|
const register = {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
password: z.string().min(6).max(255),
|
password: z.string().min(6).max(255),
|
||||||
username: z.string().min(4).max(26),
|
username: z.string().min(2).max(255),
|
||||||
}),
|
}),
|
||||||
params: z.object({}),
|
params: z.object({}),
|
||||||
query: z.object({}),
|
query: z.object({}),
|
||||||
|
|||||||
@@ -3,10 +3,39 @@ import { idValidation } from './shared.validation';
|
|||||||
|
|
||||||
const detail = {
|
const detail = {
|
||||||
body: z.object({}),
|
body: z.object({}),
|
||||||
params: z.object({ ...idValidation('id') }),
|
params: z.object({ ...idValidation('userId') }),
|
||||||
|
query: z.object({}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const createUser = {
|
||||||
|
body: z.object({
|
||||||
|
displayName: z.optional(z.string()),
|
||||||
|
password: z.string().min(6).max(255),
|
||||||
|
username: z.string().min(2).max(255),
|
||||||
|
}),
|
||||||
|
params: z.object({}),
|
||||||
|
query: z.object({}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteUser = {
|
||||||
|
body: z.object({}),
|
||||||
|
params: z.object({ ...idValidation('userId') }),
|
||||||
|
query: z.object({}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateUser = {
|
||||||
|
body: z.object({
|
||||||
|
displayName: z.optional(z.string().min(2).max(255)),
|
||||||
|
password: z.optional(z.string().min(6).max(255)),
|
||||||
|
username: z.optional(z.string().min(2).max(255)),
|
||||||
|
}),
|
||||||
|
params: z.object({ ...idValidation('userId') }),
|
||||||
query: z.object({}),
|
query: z.object({}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const usersValidation = {
|
export const usersValidation = {
|
||||||
|
createUser,
|
||||||
|
deleteUser,
|
||||||
detail,
|
detail,
|
||||||
|
updateUser,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user