From 6e7e3e66f5d76ac0fcb176447f9f711d548dbc36 Mon Sep 17 00:00:00 2001 From: Jagraj Aulakh Date: Sun, 19 Mar 2023 02:10:12 -0400 Subject: [PATCH 1/4] #13 Made login page that actually send request to backend. CORS stuff. --- backend/app/__init__.py | 2 -- backend/app/routes.py | 14 ++++---- backend/main.py | 6 ++-- backend/requirements.txt | 2 ++ frontend/src/components/MyNavbar.jsx | 2 +- frontend/src/pages/LoginPage.jsx | 50 +++++++++++++++++++++++----- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/backend/app/__init__.py b/backend/app/__init__.py index 072d86e..4debff8 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -8,8 +8,6 @@ from config import Config db = SQLAlchemy() migrate = Migrate() login = LoginManager() -login.login_view = "login" -login.login_message = "Please log in to access this page." def create_app(config_class=Config): diff --git a/backend/app/routes.py b/backend/app/routes.py index e45b6ee..649411a 100644 --- a/backend/app/routes.py +++ b/backend/app/routes.py @@ -1,6 +1,6 @@ -from flask_login import login_user, logout_user +from flask_login import login_required, login_user, logout_user from app.bp import bp -from flask import Response, jsonify, request +from flask import jsonify, request from app.errors import error_response from flask_login import current_user @@ -20,10 +20,10 @@ def login_route(): if current_user.is_authenticated: return error_response(400, "A user is already logged in!") - if not data.get("user_id") or not data.get("password"): - return error_response(400, "Must supply user_id and password") + if not data.get("username") or not data.get("password"): + return error_response(400, "Must supply username and password") - user = User.query.get(data.get("user_id")) + user = User.query.filter_by(username=data["username"]).first() if not user: return error_response(400, "User not found") @@ -36,10 +36,8 @@ def login_route(): @bp.route("/logout", methods=["POST"]) +@login_required def logout_route(): - if not current_user.is_authenticated: - return error_response(400, "No users are logged in!") - resp = jsonify(current_user.to_dict()) logout_user() return resp diff --git a/backend/main.py b/backend/main.py index 1cbaba5..be9b9c8 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,10 +3,12 @@ dotenv.load_dotenv() from app import create_app, db from app.models import User +from flask_cors import CORS app = create_app() +CORS(app, supports_credentials=True, resources={r"/.*": {"origins": r".*localhost.*"}}) + @app.shell_context_processor def make_shell_context(): - return {'db': db, 'User': User} - + return {"db": db, "User": User} diff --git a/backend/requirements.txt b/backend/requirements.txt index 06f76c6..6937fee 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,6 +1,7 @@ alembic==1.10.2 click==8.1.3 Flask==2.2.3 +Flask-Cors==3.0.10 Flask-HTTPAuth==4.7.0 Flask-Login==0.6.2 Flask-Migrate==4.0.4 @@ -12,6 +13,7 @@ Jinja2==3.1.2 Mako==1.2.4 MarkupSafe==2.1.2 python-dotenv==1.0.0 +six==1.16.0 SQLAlchemy==2.0.6 typing_extensions==4.5.0 Werkzeug==2.2.3 diff --git a/frontend/src/components/MyNavbar.jsx b/frontend/src/components/MyNavbar.jsx index 658395b..f2f3d9f 100644 --- a/frontend/src/components/MyNavbar.jsx +++ b/frontend/src/components/MyNavbar.jsx @@ -1,4 +1,4 @@ -import { Nav, Container, Navbar, NavDropdown } from "react-bootstrap"; +import { Nav, Container, Navbar } from "react-bootstrap"; const MyNavbar = () => { return ( diff --git a/frontend/src/pages/LoginPage.jsx b/frontend/src/pages/LoginPage.jsx index 2699150..dc29604 100644 --- a/frontend/src/pages/LoginPage.jsx +++ b/frontend/src/pages/LoginPage.jsx @@ -1,27 +1,61 @@ -import React from "react"; -import { Col, Container, Form, Row } from "react-bootstrap"; +import React, { useState } from "react"; +import { Button, Col, Container, Form, Row } from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; +import { makeRequest } from "../utils.ts"; const LoginPage = () => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + + const sendLoginRequest = async () => { + // await makeRequest({ + // url: "http://localhost:5000/login", + // method: "POST", + // body: { username, password }, + // }) + // .then((resp) => resp.json()) + // .then((data) => { + // console.log(data); + // }); + }; + return (
- + Username - - + + { + setUsername(e.target.value); + }} + /> - + Password - - + + { + setPassword(e.target.value); + }} + /> + + + + + + -- 2.49.1 From abb1769c48c44110a5edca99d7de514633442b45 Mon Sep 17 00:00:00 2001 From: Jagraj Aulakh Date: Sun, 19 Mar 2023 02:17:36 -0400 Subject: [PATCH 2/4] #13 Show error alert on invalid response --- frontend/src/pages/LoginPage.jsx | 34 +++++++++++++++++++++----------- frontend/src/utils.ts | 11 +++++++++++ 2 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 frontend/src/utils.ts diff --git a/frontend/src/pages/LoginPage.jsx b/frontend/src/pages/LoginPage.jsx index dc29604..14672bc 100644 --- a/frontend/src/pages/LoginPage.jsx +++ b/frontend/src/pages/LoginPage.jsx @@ -1,29 +1,39 @@ import React, { useState } from "react"; -import { Button, Col, Container, Form, Row } from "react-bootstrap"; +import { Button, Col, Container, Form, Row, Alert} from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; import { makeRequest } from "../utils.ts"; const LoginPage = () => { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); + const [error, setError] = useState(null); - const sendLoginRequest = async () => { - // await makeRequest({ - // url: "http://localhost:5000/login", - // method: "POST", - // body: { username, password }, - // }) - // .then((resp) => resp.json()) - // .then((data) => { - // console.log(data); - // }); + const sendLoginRequest = async (e) => { + e.preventDefault(); + await makeRequest({ + url: "http://localhost:5000/login", + method: "POST", + body: { username, password }, + }) + .then((resp) => resp.json()) + .then((data) => { + if (data.error) { + setError(data); + return; + } + console.log(data); + window.location.href = "/"; + }); }; return ( + { error && ( + ERROR! {error.message} + )} - + Username diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts new file mode 100644 index 0000000..c7b116f --- /dev/null +++ b/frontend/src/utils.ts @@ -0,0 +1,11 @@ +const makeRequest = ({ url, method, body }): Promise => { + return fetch(url, { + method: method, + credentials: "include", + body: JSON.stringify(body), + headers: { "content-type": "application/json" }, + mode: "cors", + }); +}; + +export { makeRequest }; -- 2.49.1 From 851a784aaae891dd20d5aa43a8c132d5740c2c58 Mon Sep 17 00:00:00 2001 From: Jagraj Aulakh Date: Sun, 19 Mar 2023 02:22:23 -0400 Subject: [PATCH 3/4] #13 Error alert formatting --- frontend/src/pages/HomePage.jsx | 9 +++++++++ frontend/src/pages/LoginPage.jsx | 12 ++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/HomePage.jsx b/frontend/src/pages/HomePage.jsx index 527d63a..f016608 100644 --- a/frontend/src/pages/HomePage.jsx +++ b/frontend/src/pages/HomePage.jsx @@ -1,7 +1,16 @@ +import { useEffect } from "react"; import { Container } from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; const HomePage = () => { + {/*{current_user} = use context*/} + const current_user = null; + + useEffect(()=>{ + if (!current_user) { + window.location.replace("/login"); + } + }, []); return (
diff --git a/frontend/src/pages/LoginPage.jsx b/frontend/src/pages/LoginPage.jsx index 14672bc..220eb56 100644 --- a/frontend/src/pages/LoginPage.jsx +++ b/frontend/src/pages/LoginPage.jsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { Button, Col, Container, Form, Row, Alert} from "react-bootstrap"; +import { Button, Col, Container, Form, Row, Alert } from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; import { makeRequest } from "../utils.ts"; @@ -9,7 +9,7 @@ const LoginPage = () => { const [error, setError] = useState(null); const sendLoginRequest = async (e) => { - e.preventDefault(); + e?.preventDefault(); await makeRequest({ url: "http://localhost:5000/login", method: "POST", @@ -29,8 +29,12 @@ const LoginPage = () => { return ( - { error && ( - ERROR! {error.message} + {error && ( + + + {error.message} + + )} -- 2.49.1 From 8b9bc96b93ec8d55b793e54ab9285297bcc5982b Mon Sep 17 00:00:00 2001 From: Jagraj Aulakh Date: Sun, 19 Mar 2023 14:55:51 -0400 Subject: [PATCH 4/4] #13 Got auth logic working --- frontend/src/App.js | 7 +++++-- frontend/src/components/MyNavbar.jsx | 7 ++++++- frontend/src/contexts/UserContext.jsx | 30 +++++++++++++++++++++++++++ frontend/src/pages/HomePage.jsx | 17 ++++++++------- frontend/src/pages/LoginPage.jsx | 19 ++++++++++++++--- 5 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 frontend/src/contexts/UserContext.jsx diff --git a/frontend/src/App.js b/frontend/src/App.js index e77fd2e..7a5767a 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -2,12 +2,15 @@ import "./App.css"; import { Route } from "wouter"; import HomePage from "./pages/HomePage"; import LoginPage from "./pages/LoginPage"; +import { UserContextProvider } from "./contexts/UserContext"; function App() { return (
- - + + + +
); } diff --git a/frontend/src/components/MyNavbar.jsx b/frontend/src/components/MyNavbar.jsx index f2f3d9f..1cd46ff 100644 --- a/frontend/src/components/MyNavbar.jsx +++ b/frontend/src/components/MyNavbar.jsx @@ -1,6 +1,9 @@ +import { useContext } from "react"; import { Nav, Container, Navbar } from "react-bootstrap"; +import UserContext from "../contexts/UserContext"; const MyNavbar = () => { + const { currentUser } = useContext(UserContext); return ( @@ -9,7 +12,9 @@ const MyNavbar = () => { diff --git a/frontend/src/contexts/UserContext.jsx b/frontend/src/contexts/UserContext.jsx new file mode 100644 index 0000000..c0b3a97 --- /dev/null +++ b/frontend/src/contexts/UserContext.jsx @@ -0,0 +1,30 @@ +import { createContext, useMemo, useState } from "react"; + +const UserContext = createContext({}); + +const UserContextProvider = ({ children }) => { + + const [currentUser, setCurrentUser] = useState(undefined); + + // useMemo does not wait for after render, like useEffect. + useMemo(()=>{ + setCurrentUser(JSON.parse(localStorage.getItem("currentUser"))); + },[]); + + const contextValues = { + currentUser, + setCurrentUser: (data) => { + localStorage.setItem("currentUser", JSON.stringify(data)) + setCurrentUser(data); + }, + }; + + return ( + + {children} + + ); +}; + +export default UserContext; +export { UserContextProvider }; diff --git a/frontend/src/pages/HomePage.jsx b/frontend/src/pages/HomePage.jsx index f016608..ebc5b5d 100644 --- a/frontend/src/pages/HomePage.jsx +++ b/frontend/src/pages/HomePage.jsx @@ -1,16 +1,17 @@ -import { useEffect } from "react"; +import { useContext, useEffect } from "react"; import { Container } from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; +import UserContext from "../contexts/UserContext"; const HomePage = () => { - {/*{current_user} = use context*/} - const current_user = null; + const { currentUser } = useContext(UserContext); + + useEffect(() => { + if (!currentUser?.id) { + window.location.replace("/login"); + } + }, [currentUser]); - useEffect(()=>{ - if (!current_user) { - window.location.replace("/login"); - } - }, []); return (
diff --git a/frontend/src/pages/LoginPage.jsx b/frontend/src/pages/LoginPage.jsx index 220eb56..21ef318 100644 --- a/frontend/src/pages/LoginPage.jsx +++ b/frontend/src/pages/LoginPage.jsx @@ -1,6 +1,7 @@ -import React, { useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import { Button, Col, Container, Form, Row, Alert } from "react-bootstrap"; import MyNavbar from "../components/MyNavbar"; +import UserContext from "../contexts/UserContext"; import { makeRequest } from "../utils.ts"; const LoginPage = () => { @@ -8,6 +9,19 @@ const LoginPage = () => { const [password, setPassword] = useState(""); const [error, setError] = useState(null); + const { currentUser, setCurrentUser } = useContext(UserContext); + + useEffect(() => { + console.log(currentUser); + if (currentUser?.id) { + gotoHome(); + } + }, [currentUser]); + + const gotoHome = () => { + window.location.href = "/"; + }; + const sendLoginRequest = async (e) => { e?.preventDefault(); await makeRequest({ @@ -21,8 +35,7 @@ const LoginPage = () => { setError(data); return; } - console.log(data); - window.location.href = "/"; + setCurrentUser(data); }); }; -- 2.49.1