Skip to content

Commit

Permalink
Merge pull request #140 from FernFinder/loginquizpathline
Browse files Browse the repository at this point in the history
Login page to quiz redirection + Stat Change API
  • Loading branch information
dusek2 authored Apr 24, 2024
2 parents 829c569 + c681447 commit 751087e
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 11 deletions.
16 changes: 10 additions & 6 deletions app/src/pages/login/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,20 @@ const Login = () => {
//Got a response, now let's handle it

.then(function (response) {
// Login successful! Let's go to the home page.
window.location.href = '/home'
console.log(response);

// Login successful!
//If quiz is not done yet redirect to it, else go to home page
if(response.data.doQuiz){
window.location.href = '/quiz';
console.log(response);
}else{
window.location.href = '/home';
console.log(response);
}
})
.catch(function (error) {
// Uh oh, bad login! Let's see what went wrong.
console.log(error);
})

})
}

return (
Expand Down
31 changes: 31 additions & 0 deletions app/src/pages/quiz/QuizPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PageContent from "../../components/PageContent";
import styles from "./QuizPage.module.css";
import questionsData from "./quiz_questions.json";
import { useFontSize } from '../../contexts/FontSizeContext';
import axios from "axios";

const QuizPage = () => {
const { fontSize, darkMode } = useFontSize();
Expand Down Expand Up @@ -55,6 +56,35 @@ const QuizPage = () => {
}
};

async function handleFinishQuizClick() {

axios.defaults.baseURL = 'http://localhost:9000';

/*
Axios makes a post request to the address, feeding in the user inputed
credentials. Await for a response.
*/
const response = await axios.post('/users/changestats', {
//These must be rounded. Otherwise expect floating point errors :(
newMeStat: Math.floor(healthPercentage),
newLoveStat: Math.floor(relationshipsPercentage),
newWorkStat: Math.floor(professionalPercentage)
},
{ withCredentials: true //Required for cookies.
})

//Got a response, now let's handle it

.then(function (response) {
//Quiz was successful! Let's go to the home page.
window.location.href = '/home';
})
.catch(function (error) {
// Uh oh, bad quiz submission! Let's see what went wrong.
console.log(error);
})
};

// Calculate the total possible points for each category
const totalPossiblePoints = (totalQuestions / 3) * 5; // Assuming each question has a max score of 5

Expand Down Expand Up @@ -124,6 +154,7 @@ const QuizPage = () => {
<div>Health Score: {healthPercentage.toFixed(2)}%</div>
<div>Professional Score: {professionalPercentage.toFixed(2)}%</div>
<div>Relationships Score: {relationshipsPercentage.toFixed(2)}%</div>
<button onClick={handleFinishQuizClick} className={styles.answerOptions}>Finish Quiz</button>
</div>
)}
</div>
Expand Down
10 changes: 8 additions & 2 deletions backend/routes/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,14 @@ router.post('/submit', async (req, res, next) => {
httpOnly: false,
});

//We signed in successfully! Return status 200.
res.status(200).json({ message: "Signed in successfully"});
//We signed in successfully!

//Check if the quiz needs to be done
if(!user.completedQuiz)
return res.status(200).json({ message: "Signed in successfully", doQuiz: true });

//Quiz is already complete, go to home page
return res.status(200).json({ message: "Signed in successfully", doQuiz: false });

} catch (error) {
res.status(500).json({ message: error.message });
Expand Down
23 changes: 23 additions & 0 deletions backend/routes/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ router.post('/', async (req, res, next) => {
}
});

// POST /users/changestats - change stats of logged in user
router.post('/changestats', async (req, res) => {
try {
// access user from request which has been
// attached by the userVerification middleware
const user = req.user;
// if no user found, send back 404
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
// send back the user
await user.updateOne({ 'stats.MeStat': req.body.newMeStat });
await user.updateOne({ 'stats.LoveStat': req.body.newLoveStat });
await user.updateOne({ 'stats.WorkStat': req.body.newWorkStat });
await user.updateOne({ completedQuiz: true });
return res.status(200).json({ message: 'Stats Updated' });
}
catch (error) {
// send back 500 status and error message
res.status(500).json({ message: error.message });
}
});

// GET /users/me - retrieve logged in user
router.get('/me', async (req, res, next) => {
try {
Expand Down
19 changes: 17 additions & 2 deletions backend/tests/login.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,30 @@ describe("POST /login/submit", () => {
expect(response.body.message).toBe('Password not found');
});

it("it should login the user", async () => {
// Check a user email that is in database
it("it should login a user with unfinished quiz", async () => {
// Check a user that is in database that has not finished quiz
newUser.email = 'backendtesting3927492130@test.net';
newUser.password = 'password';
// Post request to create a new user
const response = await request(app).post("/login/submit").send(newUser);
// check if correct user in reponse
expect(response.statusCode).toBe(200);
expect(response.body.message).toBe('Signed in successfully');
// check if the request indicated that the quiz needs to be done
expect(response.body.doQuiz).toBe(true);
});

it("it should login a user with finished quiz", async () => {
// Check a user that is in database that has finished quiz
newUser.email = 'login@testing.com';
newUser.password = 'password';
// Post request to create a new user
const response = await request(app).post("/login/submit").send(newUser);
// check if correct user in reponse
expect(response.statusCode).toBe(200);
expect(response.body.message).toBe('Signed in successfully');
// check if the request indicated that the quiz has been done
expect(response.body.doQuiz).toBe(false);
});

it("it should throw an error", async () => {
Expand Down
43 changes: 43 additions & 0 deletions backend/tests/users.notfound.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const request = require("supertest");
const sinon = require('sinon');
const middleware = require('../middleware/auth.js');
const mongoose = require('mongoose');
var app;

beforeAll(async () => {
//Replace the middleware function with a fake function that passes the request through.
sinon.stub(middleware, "userVerification")
.callsFake(async function userVerification(req, res, next) {
return next();
});

//You need to declare this after the fake function is made
app = require("../app");
});

afterAll(async () => {
//Restore middleware function to the original state
middleware.userVerification.restore();
mongoose.disconnect;
});

// test user stat change
describe("POST /users/changestats", () => {
it("it should return 404 for no user found", async () => {
// request stat update
const response = await request(app).post("/users/changestats");
// check for error 404, user not found
expect(response.statusCode).toBe(404);
expect(response.body.message).toBe('User not found');
});
});

describe("GET /users/me", () => {
it("it should get a user's stats", async () => {
// request stats
const response = await request(app).get("/users/me");
// check for error 404, user not found
expect(response.statusCode).toBe(404);
expect(response.body.message).toBe('User not found');
});
});
31 changes: 30 additions & 1 deletion backend/tests/users.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const request = require("supertest");
const sinon = require('sinon');
const middleware = require('../middleware/auth.js');
const User = require('../models/user');
const mongoose = require('mongoose');
var app;

Expand All @@ -15,7 +16,10 @@ const newUser = {
beforeAll(async () => {
//Replace the middleware function with a fake function that passes the request through.
sinon.stub(middleware, "userVerification")
.callsFake(function userVerification(req, res, next) {
.callsFake(async function userVerification(req, res, next) {
//provide a test user for API to use
const user = await User.findOne({ email: "backendtesting3927492130@test.net" });
req.user = user;
return next();
});

Expand All @@ -24,6 +28,10 @@ beforeAll(async () => {
});

afterAll(async () => {

const user = await User.findOne({ email: "backendtesting3927492130@test.net" });
await user.updateOne({ completedQuiz: false });

//Restore middleware function to the original state
middleware.userVerification.restore();
mongoose.disconnect;
Expand Down Expand Up @@ -80,3 +88,24 @@ describe("DELETE /users/:email", () => {
});

/* << ChatGPT4 assistance */

// test user stat change
describe("POST /users/changestats", () => {
it("it should update a user's stats", async () => {
// request stat change
const response = await request(app).post("/users/changestats")
.send({newMeStat: 100, newLoveStat: 100, newWorkStat: 100});
// check for success
expect(response.statusCode).toBe(200);
expect(response.body.message).toBe('Stats Updated');
});
});

describe("GET /users/me", () => {
it("it should get a user's stats", async () => {
// request stats
const response = await request(app).get("/users/me");
// check for success
expect(response.statusCode).toBe(200);
});
});

0 comments on commit 751087e

Please sign in to comment.