Skip to content

Commit

Permalink
add logout - get posts, single post, delete post to backend and add t…
Browse files Browse the repository at this point in the history
…hose functionalities to frontend
  • Loading branch information
mamadfar committed Mar 3, 2023
1 parent 146e9c9 commit 934f0fb
Show file tree
Hide file tree
Showing 22 changed files with 275 additions and 154 deletions.
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/markdown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/node-mysql-react-blog.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 17 additions & 8 deletions api/src/controllers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,29 @@ export const login = (
data[0].password
);
if (!isPasswordCorrect) {
return res.status(400).json("Wrong username or password!");
};
return res.status(400).json("Wrong username or password!");
}

//? jwt token
const token = jwt.sign({ id: data[0].id }, "jwtkey");
const {password, ...other} = data[0];
const { password, ...other } = data[0];

//? cookie
res.cookie("access_token", token, {
httpOnly: true,
path: "/login"
}).status(200).json(other);
res
.cookie("access_token", token, {
httpOnly: true
})
.status(200)
.json(other);
});
};

//! Logout
export const logout = (req: Request, res: Response) => {};
export const logout = (req: Request, res: Response) => {
res.clearCookie("access_token", {
sameSite: "none",
secure: true,
})
.status(200)
.json("User has been logged out.");
};
46 changes: 43 additions & 3 deletions api/src/controllers/posts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
import express, {Request, Response} from "express";
import { Request, Response } from "express";
import { verify } from "jsonwebtoken";
import { db } from "../db";

export const getPosts = (req: Request, res: Response) => {
const query = req.query.cat
? "SELECT * FROM posts WHERE cat = ?"
: "SELECT * FROM posts";

db.query(query, [req.query.cat], (err, data) => {
if (err) return res.status(500).json(err);
return res.status(200).json(data);
});
};

export const getPost = (req: Request, res: Response) => {
const query =
"SELECT `username`, `title`, `desc`, p.img, u.img AS userImg, `cat`, `date` FROM users u JOIN posts p ON u.id=p.uid WHERE p.id = ?";

db.query(query, [req.params.id], (err, data) => {
if (err) return res.status(500).json(err);
return res.status(200).json(data[0]);
});
};
export const deletePost = (req: Request, res: Response) => {
const token = req.cookies.access_token;
if (!token) return res.status(401).json("Not authenticated!");

verify(token, "jwtkey", (err: any, userInfo: any) => {
if (err) return res.status(403).json("Token is not valid!");
const query = "DELETE FROM posts WHERE `id` = ? AND `uid` = ?";
const postId = req.params.id;

db.query(query, [postId, userInfo.id], (err, data) => {
if (err) return res.status(403).json("You can delete only your post!");
return res.status(204).json("Post has been deleted.");
});
});
};
export const updatePost = (req: Request, res: Response) => {
res.json("from controller");
};
export const addPost = (req: Request, res: Response) => {
res.json("from controller")
};
res.json("from controller");
};
2 changes: 1 addition & 1 deletion api/src/routes/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ const router = express.Router();

router.post("/register", register);
router.post("/login", login);
router.post("/logout", logout);
router.get("/logout", logout);

export default router;
8 changes: 6 additions & 2 deletions api/src/routes/posts.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import express from "express";
import { addPost } from './../controllers/posts';
import { addPost, deletePost, getPost, getPosts, updatePost } from "./../controllers/posts";

const router = express.Router();

router.get("/", addPost);
router.get("/", getPosts);
router.get("/:id", getPost);
router.post("/", addPost);
router.delete("/:id", deletePost);
router.put("/:id", updatePost);

export default router;
2 changes: 1 addition & 1 deletion client/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 14 additions & 25 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/js-cookie": "^3.0.3",
"@types/node": "^16.18.12",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"axios": "^1.3.4",
"js-cookie": "^3.0.1",
"moment": "^2.29.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-quill": "^2.0.0",
Expand Down
7 changes: 5 additions & 2 deletions client/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import "./Header.scss";
import logo from "../assets/img/logo.png";
import {Link} from "react-router-dom";
import {useAuth} from "../hooks/useAuth";

const Header = () => {
const {user, logout} = useAuth();

return (
<header>
<div className="navbar">
Expand Down Expand Up @@ -31,8 +34,8 @@ const Header = () => {
<Link to="/?cat=food" className="link">
<h6>FOOD</h6>
</Link>
<span>John</span>
<span>Logout</span>
<span>{user?.username}</span>
{user ? <span onClick={logout}>Logout</span> : <Link to="/login" className="link">Login</Link>}
<span className="write-link">
<Link to="/write" className="link">Write</Link>
</span>
Expand Down
10 changes: 3 additions & 7 deletions client/src/context/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import {Context, createContext} from "react";
import {createContext} from "react";
import {IUser} from "../model/user.model";

interface IAuthContext {
user: IUser,
login: (user: Omit<IUser, "email">) => any,
login: (user: Omit<IUser, "email">) => unknown,
logout: () => any
}

const AuthContext = createContext<IAuthContext>({
user: {
username: "",
email: "",
password: ""
},
user: JSON.parse(localStorage.getItem("user") as string),
login: (user) => {},
logout: () => {}
});
Expand Down
32 changes: 15 additions & 17 deletions client/src/hooks/useAuth.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import {FC, ReactNode, useCallback, useContext, useReducer} from "react";
import AuthContext from "../context/AuthContext";
import Cookie from "js-cookie";
import {AUTH_ACTION} from "../model/auth.model";
import {loginService, logoutService} from "../services/auth.service";
import {IUser} from "../model/user.model";
import {useNavigate} from "react-router-dom";

export const useAuth = () => {
const context = useContext(AuthContext);
Expand All @@ -15,44 +13,44 @@ export const useAuth = () => {
};

interface IInitialState {
user: IUser
user: IUser,
// status: "undetermined" | "pending" | "fulfilled" | "rejected"
}

const initialState: IInitialState = {
user: {
username: "",
password: "",
email: ""
}
user: JSON.parse(localStorage.getItem("user") as string),
}

const authReducer = (state: typeof initialState, action: AUTH_ACTION) => {
switch (action.type) {
case "LOGIN":
case "LOGIN": {
localStorage.setItem("user", JSON.stringify(action.payload));
return {...state, user: action.payload}
}
case "LOGOUT": {
localStorage.removeItem("user");
return {...state, user: ""}
}
default:
return state;
}
}

const AuthProvider: FC<{ children: ReactNode }> = ({children}) => {
const [state, dispatch] = useReducer(authReducer, initialState);
// const navigate = useNavigate();

const value = {
...state,
login: useCallback(async (user: Omit<IUser, "email">) => {
const {data, status, headers} = await loginService(user);
const {data, status} = await loginService(user);
if (status === 200) {
dispatch({type: "LOGIN", payload: data});
// navigate("/")
// Cookie.set("access_token", headers["Set-Cookie"])
// console.log()
}
}, []),
return status;
}, [dispatch]),
logout: useCallback(async () => {
// const {data, status} = await logoutService();
// dispatch({type: "LOGIN", payload: data})
const {status} = await logoutService();
if (status === 200) dispatch({type: "LOGOUT"});
}, [])
}

Expand Down
2 changes: 1 addition & 1 deletion client/src/model/auth.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

type TYPE = "LOGIN" | "LOGOUT"

export type AUTH_ACTION = {type: TYPE, payload: any}
export type AUTH_ACTION = {type: "LOGIN", payload: any} | {type: "LOGOUT"}
Loading

0 comments on commit 934f0fb

Please sign in to comment.