fix

parent f54153c9
import { ProductForm } from "@/components/ProductForm";
import { createProduct } from "@/features/productsSlice";
import { useAppDispatch } from "@/store/hook";
import { UserRoles } from "@/features/usersSlice";
import { useAppDispatch, useAppSelector } from "@/store/hook";
import { Typography } from "@mui/material";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
export function NewProductForm() {
const dispatch = useAppDispatch();
const navigate = useNavigate();
const {user} = useAppSelector(state => state.users)
const onProductFormSubmit = async (product: Omit<FormData, "id">) => {
await dispatch(createProduct(product));
navigate("/");
}
// useEffect(() => {
// if(user?.role !== UserRoles.admin) navigate('/')
// }, [user])
return <>
<Typography variant="h4">New product</Typography>
<ProductForm onProductFormSubmit={onProductFormSubmit}/>
......
......@@ -4,9 +4,11 @@ import { Button, Grid, Typography } from '@mui/material';
import { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { ProductItem } from './ProductItem';
import { UserRoles } from '@/features/usersSlice';
export function Products() {
const dispatch = useAppDispatch();
const { user } = useAppSelector((state) => state.users);
const { products } = useAppSelector((state) => state.products);
useEffect(() => {
......@@ -27,11 +29,14 @@ export function Products() {
))}
</Grid>
<Grid item>
<Button color="primary" component={Link} to={'/products/new'}>
Add product
</Button>
</Grid>
{
user?.role !== UserRoles.admin &&
<Grid item>
<Button color="primary" component={Link} to={'/products/new'}>
Add product
</Button>
</Grid>
}
</Grid>
);
}
......
......@@ -25,12 +25,14 @@ const initialState: State = {
};
export const fetchProducts = createAsyncThunk('fetch/products', async () => {
return await axiosApiClient.get<IProductState[]>('/products').then(res => res.data);
const token = localStorage.getItem('token')
return await axiosApiClient.get<IProductState[]>('/products', {headers: {Authorization: token}}).then(res => res.data);
});
export const createProduct = createAsyncThunk('create/product',
async (payload: Omit<FormData, "id">) => {
return axiosApiClient.post<IProduct>("/products/create", payload)
const token = localStorage.getItem('token')
return axiosApiClient.post<IProduct>("/products/create", payload, {headers: {Authorization: token}})
.then(res => res.data);
});
......
......@@ -13,6 +13,12 @@ export interface IUserState {
username: string;
displayName: string;
token: string;
role: UserRoles
}
export enum UserRoles {
user = 'user',
admin = 'admin'
}
interface State {
......
......@@ -12,7 +12,7 @@ export class UserController {
this.service = new UserService();
}
signIn: RequestHandler = async (req, res): Promise<void> => {
signIn: RequestHandler = async (req, res): Promise<void> => {
try {
const signInDto = plainToInstance(SignInUserDto, req.body)
const user = await this.service.signIn(signInDto)
......
......@@ -4,7 +4,6 @@ import { Product } from "@/entities/product.entity";
import { DataSource } from "typeorm";
import { faker } from '@faker-js/faker';
import { Seeder, SeederFactoryManager } from "typeorm-extension";
export default class MainSeeder implements Seeder {
public async run(dataSource: DataSource, factoryManager: SeederFactoryManager): Promise<any> {
const userFactory = factoryManager.get(User)
......
import { Entity, PrimaryGeneratedColumn, Column, Unique } from "typeorm";
import bcrypt from 'bcrypt';
import { UserRoles } from "@/interfaces/IUser.interface";
const SALT_WORK_FACTOR = 10;
@Entity()
......@@ -20,6 +21,9 @@ export class User {
@Column({nullable: true})
displayName!: string
@Column({default: UserRoles.user})
role!: string
async comparePassword(password: string): Promise<boolean> {
return await bcrypt.compare(password, this.password);
}
......
import { Request } from 'express';
import { IUser } from './IUser.interface';
export interface RequestWithUser extends Request {
user?: IUser;
}
\ No newline at end of file
......@@ -3,4 +3,10 @@ export interface IUser {
username: string
password?: string
displayName?: string
role: string
}
export enum UserRoles {
user = 'user',
admin = 'admin'
}
\ No newline at end of file
import { RequestHandler } from "express";
import { UserService } from "@/services/user.service";
import { RequestWithUser } from "@/interfaces/IRequest.interface";
const userService = new UserService()
export const authValidate: RequestHandler = async (req: RequestWithUser, res, next): Promise<any> => {
try {
const token = req.header('Authorization')
if(!token) return res.status(401).send({message: 'Invalide Token'})
const user = await userService.validateToken(token)
if(!user) return res.status(401).send({message: 'User Not Found'})
req.user = user
next()
} catch (e) {
return res.status(500).send({message: 'Internal error'})
}
}
\ No newline at end of file
import { RequestWithUser } from "@/interfaces/IRequest.interface";
import { Response, NextFunction } from "express";
export function checkRole(...allowedRoles: string[]) {
return (req: RequestWithUser, res: Response, next: NextFunction) => {
const user = req.user
if (user && allowedRoles.includes(user.role)) {
next()
} else {
res.status(403).send({ error: 'Permission denied' })
}
}
}
\ No newline at end of file
import { Router } from 'express';
import { ArticleController } from '../controllers/article.controller';
import { IRoute } from '../interfaces/IRoute.interface';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
export class ArticleRoute implements IRoute {
public path = '/articles';
......@@ -13,8 +15,8 @@ export class ArticleRoute implements IRoute {
}
private init() {
this.router.get('/', this.controller.getAllArticles);
this.router.get('/:id', this.controller.getArticle);
this.router.post('/create', this.controller.createArticle);
this.router.get('/', authValidate, this.controller.getAllArticles);
this.router.get('/:id', authValidate, this.controller.getArticle);
this.router.post('/create', authValidate, checkRole('admin'), this.controller.createArticle);
}
}
import { CategoryController } from '@/controllers/category.controller';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
import { Router } from 'express';
export class CategoryRoute {
......@@ -12,8 +14,8 @@ export class CategoryRoute {
}
private init() {
this.router.get('/', this.controller.getAllCategories);
this.router.get('/:id', this.controller.getCategory);
this.router.post('/create',this.controller.createCategory);
this.router.get('/', authValidate, this.controller.getAllCategories);
this.router.get('/:id', authValidate, this.controller.getCategory);
this.router.post('/create', authValidate, checkRole('admin'), this.controller.createCategory);
}
}
import { ProductController } from '@/controllers/product.controller';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
import upload from '@/middlewares/storage';
import { Router } from 'express';
......@@ -13,8 +15,8 @@ export class ProductRoute {
}
private init() {
this.router.get('/', this.controller.getAllProducts);
this.router.get('/:id', this.controller.getProduct);
this.router.post('/create', upload.single('image') ,this.controller.createProduct);
this.router.get('/', authValidate, this.controller.getAllProducts);
this.router.get('/:id', authValidate, this.controller.getProduct);
this.router.post('/create', authValidate, checkRole('admin'), upload.single('image') ,this.controller.createProduct);
}
}
import { Router } from 'express';
import { IRoute } from '../interfaces/IRoute.interface';
import { UserController } from '@/controllers/user.controller';
export class UserRoute implements IRoute {
public path = '/user';
public router = Router();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment