Skip to content

Commit

Permalink
Author authentication (#56)
Browse files Browse the repository at this point in the history
Change Lists:
- Implemented endpoints to server login and signup purpose
- Updated `Author` model by adding `user` field for authentication
- Added `Login` and `SignUp` components on frontend side
- Added `react-toastify` library for displaying toast message

Todo:
- Implement the logic to restrict certains routes when not logged in

Guide on testing:

- Please run `migrate` and `make migrations` on server before you run
the server since there are changes to the database.

- For testing only the 2 new endpoints (using Postman)
>- signup: Currently returns status code 200 on succesful sign up, 409
on existing username and 400 on others.
![Screenshot 2023-10-23 at 12 09
36 AM](https://github.com/uofa-cmput404/404f23project-404-team-not-found/assets/54903938/ac442736-c522-41c2-9890-3f5deaa71529)

>- login: Currently returns status code 201 on succesful login, 401 on
wrong password and 404 on not existing username.
![Screenshot 2023-10-23 at 12 12
23 AM](https://github.com/uofa-cmput404/404f23project-404-team-not-found/assets/54903938/f3303f4c-0d81-4491-be68-7945ec609d0c)

- For testing on the frontend side
>- at `/signup/`, there are currently 5 fields. Any errors will have a
toast message pop up. Succesful display a success message and redirect
to `/login/`
>- at `/login/`, there are currently 2 fields. Any errors will have a
toast message pop up. Succesful display a success message and redirect
to `/home-page/` and save `authToken` to localStorage (localStorage can
be found in develop tools).
  • Loading branch information
nluu175 authored Oct 23, 2023
2 parents 0f91ddb + bc149cb commit 2de8514
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 26 deletions.
63 changes: 55 additions & 8 deletions client/package-lock.json

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

4 changes: 3 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"react-dom": "^18.2.0",
"react-router-dom": "^6.17.0",
"react-scripts": "5.0.1",
"typescript": "^5.2.2",
"react-toastify": "^9.1.3",
"toastify-js": "^1.12.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4"
},
"scripts": {
Expand Down
30 changes: 25 additions & 5 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,34 @@ import Login from "./components/authentication/Login";
import SignUp from "./components/authentication/SignUp";

import "./App.css";
import { ToastContainer } from "react-toastify";
import { getToken } from "./utils/localStorageUtils";

const App = () => {
// TODO: Find a way to validate token
// TODO: use userToken to restrict access for not logged in status
const userToken = getToken();

return (
<Routes>
<Route path="/home-page" element={<HomePage />} />
<Route path="/login" element={<Login />} />
<Route path="/sign-up" element={<SignUp />} />
</Routes>
<>
<ToastContainer
position="top-center"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="light"
/>
<Routes>
<Route path="/home-page" element={<HomePage />} />
<Route path="/login" element={<Login />} />
<Route path="/sign-up" element={<SignUp />} />
</Routes>
</>
);
};

Expand Down
51 changes: 45 additions & 6 deletions client/src/components/authentication/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FormEvent } from "react";
import React, { FormEvent, useState } from "react";

import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
Expand All @@ -8,8 +8,42 @@ import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";

import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";
import axios from "axios";

import { storeToken } from "../../utils/localStorageUtils";

const Login = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
username: "",
password: "",
});

const handleSubmit = (e: FormEvent) => {
e.preventDefault();

const requestUrl = "http://127.0.0.1:8000/socialdistribution/login/";

const form = new FormData();
form.append("username", formData.username);
form.append("password", formData.password);

axios
.post(requestUrl, form, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response: any) => {
storeToken(response.data.token);

toast.success("You are now logged in");

navigate("/home-page");
})
.catch((error) => {
toast.error("Wrong password or user does not exist");
});
return;
};

Expand All @@ -18,7 +52,6 @@ const Login = () => {
<CssBaseline />
<Box
sx={{
// marginTop: 8,
display: "flex",
flexDirection: "column",
justifyContent: "center",
Expand All @@ -35,11 +68,14 @@ const Login = () => {
margin="normal"
required
fullWidth
id="email"
label="Email"
name="email"
autoComplete="email"
id="username"
label="Username"
name="username"
autoComplete="username"
autoFocus
onChange={(e) => {
setFormData({ ...formData, username: e.target.value });
}}
/>
<TextField
margin="normal"
Expand All @@ -49,6 +85,9 @@ const Login = () => {
label="Password"
type="password"
id="password"
onChange={(e) => {
setFormData({ ...formData, password: e.target.value });
}}
/>
<Button
type="submit"
Expand Down
94 changes: 89 additions & 5 deletions client/src/components/authentication/SignUp.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FormEvent } from "react";
import React, { FormEvent, useState } from "react";

import Button from "@mui/material/Button";
import CssBaseline from "@mui/material/CssBaseline";
Expand All @@ -8,9 +8,62 @@ import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Container from "@mui/material/Container";

import axios from "axios";

import { toast } from "react-toastify";
import { useNavigate } from "react-router-dom";

const SignUp = () => {
const navigate = useNavigate();
const [formData, setFormData] = useState({
displayName: "",
username: "",
email: "",
password: "",
repeatPassword: "",
});

const handleSubmit = (e: FormEvent) => {
return;
e.preventDefault();

if (formData.password !== formData.repeatPassword) {
toast.error("Repeat password does not match!");
return;
}

const requestUrl = "http://127.0.0.1:8000/socialdistribution/signup/";

console.log(formData);

// check for missing fields
if (
formData.displayName === "" ||
formData.username === "" ||
formData.email === "" ||
formData.password === "" ||
formData.repeatPassword === ""
) {
toast.warning("Please fill all the missing fields!");
return;
}

const form = new FormData();
form.append("username", formData.username);
form.append("email", formData.email);
form.append("password", formData.password);
form.append("displayName", formData.displayName);

axios
.post(requestUrl, form, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response: any) => {
toast.success("You have succesfully signed up");
navigate("/login");
})
.catch((error) => {
toast.error(error.response.data.message);
});
};

return (
Expand All @@ -30,14 +83,39 @@ const SignUp = () => {
Already have an account? <Link href="/login">Log In</Link>
</Typography>
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="displayName"
label="Enter your name"
name="name"
autoFocus
onChange={(e) => {
setFormData({ ...formData, displayName: e.target.value });
}}
/>
<TextField
margin="normal"
required
fullWidth
id="username"
label="Enter your username"
name="username"
onChange={(e) => {
setFormData({ ...formData, username: e.target.value });
}}
/>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Enter your email"
name="email"
autoFocus
onChange={(e) => {
setFormData({ ...formData, email: e.target.value });
}}
/>
<TextField
margin="normal"
Expand All @@ -47,15 +125,21 @@ const SignUp = () => {
label="Create password"
type="password"
id="password"
onChange={(e) => {
setFormData({ ...formData, password: e.target.value });
}}
/>
<TextField
margin="normal"
required
fullWidth
name="repeat-password"
name="repeatPassword"
label="Confirm password"
type="password"
id="password"
id="repeatPassword"
onChange={(e) => {
setFormData({ ...formData, repeatPassword: e.target.value });
}}
/>
<Button
type="submit"
Expand Down
2 changes: 2 additions & 0 deletions client/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { ThemeProvider, createTheme } from "@mui/material/styles";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import "./index.css";
import 'react-toastify/dist/ReactToastify.css';


const theme = createTheme({
palette: {
Expand Down
Loading

0 comments on commit 2de8514

Please sign in to comment.