fix

parent f54153c9
import { ProductForm } from "@/components/ProductForm"; import { ProductForm } from "@/components/ProductForm";
import { createProduct } from "@/features/productsSlice"; 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 { Typography } from "@mui/material";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
export function NewProductForm() { export function NewProductForm() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const {user} = useAppSelector(state => state.users)
const onProductFormSubmit = async (product: Omit<FormData, "id">) => { const onProductFormSubmit = async (product: Omit<FormData, "id">) => {
await dispatch(createProduct(product)); await dispatch(createProduct(product));
navigate("/"); navigate("/");
} }
// useEffect(() => {
// if(user?.role !== UserRoles.admin) navigate('/')
// }, [user])
return <> return <>
<Typography variant="h4">New product</Typography> <Typography variant="h4">New product</Typography>
<ProductForm onProductFormSubmit={onProductFormSubmit}/> <ProductForm onProductFormSubmit={onProductFormSubmit}/>
......
...@@ -4,9 +4,11 @@ import { Button, Grid, Typography } from '@mui/material'; ...@@ -4,9 +4,11 @@ import { Button, Grid, Typography } from '@mui/material';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { ProductItem } from './ProductItem'; import { ProductItem } from './ProductItem';
import { UserRoles } from '@/features/usersSlice';
export function Products() { export function Products() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { user } = useAppSelector((state) => state.users);
const { products } = useAppSelector((state) => state.products); const { products } = useAppSelector((state) => state.products);
useEffect(() => { useEffect(() => {
...@@ -27,11 +29,14 @@ export function Products() { ...@@ -27,11 +29,14 @@ export function Products() {
))} ))}
</Grid> </Grid>
{
user?.role !== UserRoles.admin &&
<Grid item> <Grid item>
<Button color="primary" component={Link} to={'/products/new'}> <Button color="primary" component={Link} to={'/products/new'}>
Add product Add product
</Button> </Button>
</Grid> </Grid>
}
</Grid> </Grid>
); );
} }
......
...@@ -25,12 +25,14 @@ const initialState: State = { ...@@ -25,12 +25,14 @@ const initialState: State = {
}; };
export const fetchProducts = createAsyncThunk('fetch/products', async () => { 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', export const createProduct = createAsyncThunk('create/product',
async (payload: Omit<FormData, "id">) => { 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); .then(res => res.data);
}); });
......
...@@ -13,6 +13,12 @@ export interface IUserState { ...@@ -13,6 +13,12 @@ export interface IUserState {
username: string; username: string;
displayName: string; displayName: string;
token: string; token: string;
role: UserRoles
}
export enum UserRoles {
user = 'user',
admin = 'admin'
} }
interface State { interface State {
......
...@@ -4,7 +4,6 @@ import { Product } from "@/entities/product.entity"; ...@@ -4,7 +4,6 @@ import { Product } from "@/entities/product.entity";
import { DataSource } from "typeorm"; import { DataSource } from "typeorm";
import { faker } from '@faker-js/faker'; import { faker } from '@faker-js/faker';
import { Seeder, SeederFactoryManager } from "typeorm-extension"; import { Seeder, SeederFactoryManager } from "typeorm-extension";
export default class MainSeeder implements Seeder { export default class MainSeeder implements Seeder {
public async run(dataSource: DataSource, factoryManager: SeederFactoryManager): Promise<any> { public async run(dataSource: DataSource, factoryManager: SeederFactoryManager): Promise<any> {
const userFactory = factoryManager.get(User) const userFactory = factoryManager.get(User)
......
import { Entity, PrimaryGeneratedColumn, Column, Unique } from "typeorm"; import { Entity, PrimaryGeneratedColumn, Column, Unique } from "typeorm";
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import { UserRoles } from "@/interfaces/IUser.interface";
const SALT_WORK_FACTOR = 10; const SALT_WORK_FACTOR = 10;
@Entity() @Entity()
...@@ -20,6 +21,9 @@ export class User { ...@@ -20,6 +21,9 @@ export class User {
@Column({nullable: true}) @Column({nullable: true})
displayName!: string displayName!: string
@Column({default: UserRoles.user})
role!: string
async comparePassword(password: string): Promise<boolean> { async comparePassword(password: string): Promise<boolean> {
return await bcrypt.compare(password, this.password); 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 { ...@@ -3,4 +3,10 @@ export interface IUser {
username: string username: string
password?: string password?: string
displayName?: 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 { Router } from 'express';
import { ArticleController } from '../controllers/article.controller'; import { ArticleController } from '../controllers/article.controller';
import { IRoute } from '../interfaces/IRoute.interface'; import { IRoute } from '../interfaces/IRoute.interface';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
export class ArticleRoute implements IRoute { export class ArticleRoute implements IRoute {
public path = '/articles'; public path = '/articles';
...@@ -13,8 +15,8 @@ export class ArticleRoute implements IRoute { ...@@ -13,8 +15,8 @@ export class ArticleRoute implements IRoute {
} }
private init() { private init() {
this.router.get('/', this.controller.getAllArticles); this.router.get('/', authValidate, this.controller.getAllArticles);
this.router.get('/:id', this.controller.getArticle); this.router.get('/:id', authValidate, this.controller.getArticle);
this.router.post('/create', this.controller.createArticle); this.router.post('/create', authValidate, checkRole('admin'), this.controller.createArticle);
} }
} }
import { CategoryController } from '@/controllers/category.controller'; import { CategoryController } from '@/controllers/category.controller';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
import { Router } from 'express'; import { Router } from 'express';
export class CategoryRoute { export class CategoryRoute {
...@@ -12,8 +14,8 @@ export class CategoryRoute { ...@@ -12,8 +14,8 @@ export class CategoryRoute {
} }
private init() { private init() {
this.router.get('/', this.controller.getAllCategories); this.router.get('/', authValidate, this.controller.getAllCategories);
this.router.get('/:id', this.controller.getCategory); this.router.get('/:id', authValidate, this.controller.getCategory);
this.router.post('/create',this.controller.createCategory); this.router.post('/create', authValidate, checkRole('admin'), this.controller.createCategory);
} }
} }
import { ProductController } from '@/controllers/product.controller'; import { ProductController } from '@/controllers/product.controller';
import { authValidate } from '@/middlewares/auth.middleware';
import { checkRole } from '@/middlewares/checkRole';
import upload from '@/middlewares/storage'; import upload from '@/middlewares/storage';
import { Router } from 'express'; import { Router } from 'express';
...@@ -13,8 +15,8 @@ export class ProductRoute { ...@@ -13,8 +15,8 @@ export class ProductRoute {
} }
private init() { private init() {
this.router.get('/', this.controller.getAllProducts); this.router.get('/', authValidate, this.controller.getAllProducts);
this.router.get('/:id', this.controller.getProduct); this.router.get('/:id', authValidate, this.controller.getProduct);
this.router.post('/create', upload.single('image') ,this.controller.createProduct); this.router.post('/create', authValidate, checkRole('admin'), upload.single('image') ,this.controller.createProduct);
} }
} }
import { Router } from 'express'; import { Router } from 'express';
import { IRoute } from '../interfaces/IRoute.interface'; import { IRoute } from '../interfaces/IRoute.interface';
import { UserController } from '@/controllers/user.controller'; import { UserController } from '@/controllers/user.controller';
export class UserRoute implements IRoute { export class UserRoute implements IRoute {
public path = '/user'; public path = '/user';
public router = Router(); 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