Skip to content

Commit

Permalink
Merge pull request #53 from BUMETCS673/HW-176-val
Browse files Browse the repository at this point in the history
Changed server structure - Added routes, controllers, and models
  • Loading branch information
abbiekuma authored Oct 5, 2024
2 parents fb62037 + 49431fd commit 9adf29e
Show file tree
Hide file tree
Showing 25 changed files with 4,825 additions and 1,049 deletions.
8 changes: 4 additions & 4 deletions code/client/src/__tests__/frontend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { render, screen } from '@testing-library/react';
import App from '../App';

// tests
test('test connection to server', async () => {
const response = await apiClient.get('/check-connection');
expect(response.status).toBe(200);
})
// test('test connection to server', async () => {
// const response = await apiClient.get('/check-connection');
// expect(response.status).toBe(200);
// })

test('renders home text', () => {
render(<App />);
Expand Down
2 changes: 2 additions & 0 deletions code/client/src/__tests__/validateGoalForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { getByRole, render, screen, waitFor, fireEvent } from '@testing-library/

import App from '../App';



test('empty input form fields', () => {
const formData = { type: '', targetValue: '' };
const result = validateGoalForm(formData);
Expand Down
2 changes: 1 addition & 1 deletion code/client/src/__tests__/validateRegistrationForm.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ test('valid input form fields', () => {
const formData = { name: 'Valid Test', email: '[email protected]', password: 'password123' };
const result = validateRegistrationForm(formData);
expect(result).toBe(true);
});
});
4 changes: 3 additions & 1 deletion code/client/src/components/CreateGoal.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import apiClient from "../services/apiClient.js";
import React, { useState } from "react";
import { validateGoalForm } from '../utils/validateGoalForm.js';
import { authenticated } from "../utils/authenticate.js";

import {
Box,
Expand All @@ -23,6 +24,7 @@ import {
} from "./style/styles.js";

function CreateGoal() {
authenticated();
const [goalFormData, setGoalFormData] = useState({
type: "",
targetValue: 0,
Expand Down Expand Up @@ -76,7 +78,7 @@ const createGoal = async (formData) => {
try {
console.log("Creating new goal with data:", formData);
// Sends a POST request to the backend with the form data
await apiClient.post("/create-goal", formData);
await apiClient.post("/api/goals/create-goal", formData);
handleGoalSuccess(); // Handle the success case
} catch (error) {
handleGoalError(error); // Handle the error case
Expand Down
6 changes: 5 additions & 1 deletion code/client/src/components/CreateUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
import apiClient from "../services/apiClient.js";
import { validateRegistrationForm } from "../utils/validateRegistrationForm.js";


import {
Box,
Typography,
Expand Down Expand Up @@ -54,7 +55,7 @@ function CreateUser() {
}

try {
await apiClient.post("/create-user", formData);
await apiClient.post("/api/users/create-user", formData);
setSuccessMessage(
"Registration successful! Redirecting to the login page..."
);
Expand Down Expand Up @@ -89,6 +90,7 @@ function CreateUser() {
<Grid2 item xs={12} md={6}>
<FormControl fullWidth>
<TextField
data-testid="txtName"
label="Name (First & Last)"
variant="filled"
fullWidth
Expand All @@ -103,6 +105,7 @@ function CreateUser() {
<Grid2 item xs={12} md={6}>
<FormControl fullWidth>
<TextField
data-testid="txtEmail"
label="Email"
variant="filled"
fullWidth
Expand All @@ -117,6 +120,7 @@ function CreateUser() {
<Grid2 item xs={12} md={6}>
<FormControl fullWidth>
<TextField
data-testid="txtPassword"
label="Password"
variant="filled"
fullWidth
Expand Down
6 changes: 4 additions & 2 deletions code/client/src/components/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ function Login({ setIsAuthenticated }) {
setError("");
// setSuccess('');
try {
const response = await apiClient.post("/login", formData);
const response = await apiClient.post("/api/users/login", formData);
const { token, userId } = response.data;
// store token
localStorage.setItem("authToken", response.data.token);
localStorage.setItem("authToken", token);
localStorage.setItem('userId', userId);
// redirect to home page
setIsAuthenticated(true);
//console.log('login success:', response.data);
Expand Down
4 changes: 2 additions & 2 deletions code/client/src/components/ManageProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function ManageProfile() {

useEffect(() => {
apiClient
.get("/manage-profile") // Fetch user profile data from the backend (e.g., /manage-profile)
.get("/api/users/manage-profile") // Fetch user profile data from the backend (e.g., /manage-profile)
.then((res) => {
setProfileData(res.data);
})
Expand Down Expand Up @@ -64,7 +64,7 @@ function ManageProfile() {
setErrorMessage('');

try {
await apiClient.post("/manage-profile", profileData);
await apiClient.post("/api/users/manage-profile", profileData);
console.log("Updating profile")
setSuccessMessage('Profile updated!');
} catch (err) {
Expand Down
2 changes: 1 addition & 1 deletion code/client/src/components/ViewUsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function ViewUsers() {

useEffect(() => {
apiClient
.get("/view-users")
.get("/api/users/view-users")
.then((res) => {
setData(res.data);
})
Expand Down
6 changes: 0 additions & 6 deletions code/package-lock.json

This file was deleted.

111 changes: 111 additions & 0 deletions code/server/__tests__/userController.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// __tests__/userController.test.js
const request = require('supertest');
const app = require('../server');
const mongoose = require('mongoose');
const User = require('../models/User'); // Your User model
const jwt = require('jsonwebtoken');

// Mock the database connection before running the tests
beforeAll(async () => {
const url = 'mongodb://127.0.0.1:27017/testDB';
await mongoose.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
});

// Close the database connection after the tests
afterAll(async () => {
await mongoose.connection.close();
});

describe('User Controller Endpoints', () => {

// Test the createUser endpoint
describe('POST /api/users/create-user', () => {
it('should create a new user', async () => {
const res = await request(app)
.post('/api/users/create-user')
.send({
name: 'Test User',
email: '[email protected]',
password: 'password123',
});

expect(res.statusCode).toEqual(201);
expect(res.body.message).toBe('User created successfully!');

// Clean up the created user after the test
await User.findOneAndDelete({ email: '[email protected]' });
});

it('should return 400 if the user already exists', async () => {
// First, create a user
await User.create({
userId: 1,
name: 'Existing User',
email: '[email protected]',
passwordHashed: await bcrypt.hash('password123', 10),
});

const res = await request(app)
.post('/api/users/create-user')
.send({
name: 'Existing User',
email: '[email protected]',
password: 'password123',
});

expect(res.statusCode).toEqual(400);
expect(res.body.message).toBe('An account with this email already exists');

// Clean up the created user after the test
await User.findOneAndDelete({ email: '[email protected]' });
});
});

// Test the loginUser endpoint
describe('POST /api/users/login', () => {
it('should log in a user and return a token', async () => {
// First, create a user to log in
const user = await User.create({
userId: 1,
name: 'Test User',
email: '[email protected]',
passwordHashed: await bcrypt.hash('password123', 10),
});

const res = await request(app)
.post('/api/users/login')
.send({
email: '[email protected]',
password: 'password123',
});

expect(res.statusCode).toEqual(200);
expect(res.body).toHaveProperty('token');
expect(res.body.message).toBe('Login successful');

// Clean up the created user after the test
await User.findOneAndDelete({ email: '[email protected]' });
});

it('should return 401 if the email or password is incorrect', async () => {
const res = await request(app)
.post('/api/users/login')
.send({
email: '[email protected]',
password: 'wrongpassword',
});

expect(res.statusCode).toEqual(401);
expect(res.body.message).toBe('Invalid email or password.');
});
});

// Test the viewUsers endpoint
describe('GET /api/users/view-users', () => {
it('should return a list of all users', async () => {
const res = await request(app).get('/api/users/view-users');
expect(res.statusCode).toEqual(200);
expect(Array.isArray(res.body)).toBe(true);
});
});
});
25 changes: 25 additions & 0 deletions code/server/config/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//This file is for defining the schema and retrieving data
//May turn this into two files moving forward (schema for one file, connection for another)

const mongoose = require('mongoose')
const dotenv = require('dotenv');
const path = require('path')

// Determine the correct .env file based on the environment
const envFile = process.env.NODE_ENV === 'production' ? '../.env.production' : '../.env.development';

// Load the appropriate .env file
// dotenv.config({ path: `../${envFile}` });
dotenv.config({ path: path.resolve(__dirname, `../${envFile}`) })

const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log(`MongoDB Connected: ${conn.connection.host}`);
} catch (error) {
console.error(`Error: ${error.message}`);
process.exit(1);
}
};

module.exports = connectDB;
28 changes: 28 additions & 0 deletions code/server/controllers/dailyEntryController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// controllers/dailyEntryController.js
const DailyEntry = require('../models/DailyEntry');

// Enter daily data
exports.enterDailyData = async (req, res) => {
try {
const { weight, steps, sleep, water, exercise } = req.body;

let lastEntry = await DailyEntry.find().sort({ dailyEntryId: -1 }).limit(1);
let newEntryId = lastEntry.length > 0 ? lastEntry[0].dailyEntryId + 1 : 1;

const newDailyEntry = new DailyEntry({
dailyEntryId: newEntryId,
userId: 10001, // TODO: Replace with logged-in user's ID
entryDate: new Date(), // Adjust according to your form logic
weight,
steps,
sleep,
water,
exercise,
});

await newDailyEntry.save();
res.status(201).json({ message: 'Daily entry created successfully!' });
} catch (error) {
res.status(500).json({ message: 'Error creating daily entry' });
}
};
29 changes: 29 additions & 0 deletions code/server/controllers/goalController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// controllers/goalController.js
const Goal = require('../models/Goal');

// Create a new goal
exports.createGoal = async (req, res) => {
try {
const { type, targetValue } = req.body;

let lastGoal = await Goal.find().sort({ goalId: -1 }).limit(1);
let newGoalId = lastGoal.length > 0 ? lastGoal[0].goalId + 1 : 1;

let unit;
switch (type) {
case 'sleep': unit = 'hours'; break;
case 'weight': unit = 'lbs'; break;
case 'steps': unit = 'steps'; break;
case 'water': unit = 'glasses'; break;
case 'exercise': unit = 'minutes'; break;
default: unit = 'unknown';
}

const newGoal = new Goal({ goalId: newGoalId, type, targetValue, unit });
await newGoal.save();

res.status(201).json({ message: 'New goal created successfully', goalId: newGoalId });
} catch (error) {
res.status(500).json({ message: 'Failed to create goal' });
}
};
Loading

0 comments on commit 9adf29e

Please sign in to comment.