diff --git a/client/src/components/charts/AnomalyChart.tsx b/client/src/components/charts/AnomalyChart.tsx index 547195d..b603edd 100644 --- a/client/src/components/charts/AnomalyChart.tsx +++ b/client/src/components/charts/AnomalyChart.tsx @@ -1,3 +1,9 @@ +/** + * This file renders a scatter chart component that visualizes anomalies detected in AWS CloudTrail data. + * It uses components from the Recharts library to build an interactive and responsive chart. + */ + +// Importing necessary components from Recharts for building the scatter chart import React from 'react'; import { ScatterChart, @@ -10,11 +16,21 @@ import { Legend, } from 'recharts'; +/** + * Represents a single data point for the scatter chart. + * - `timestamp`: The date and time of the event, formatted as a string. + * - `count`: The number of occurrences or events at the given timestamp. + */ + interface DataPoint { timestamp: string; count: number; } +/** + * Sample data representing event counts over time. + * Used for testing and visualizing the scatter chart component before integrating real data. + */ const dummyData: DataPoint[] = [ { timestamp: '2024-10-29T09:00:00Z', count: 30 }, { timestamp: '2024-10-29T09:10:00Z', count: 25 }, @@ -25,8 +41,22 @@ const dummyData: DataPoint[] = [ { timestamp: '2024-10-29T10:00:00Z', count: 45 }, ]; -const isAnomaly = (count: number): boolean => count > 70; // Define a threshold for anomalies +/** + * Determines if a given count is considered an anomaly. + * @param count - The event count at a specific timestamp. + * @returns {boolean} - Returns `true` if the count exceeds the anomaly threshold (70), otherwise `false`. + */ + +const isAnomaly = (count: number): boolean => count > 70; +/** + * AnomalyChart Component + * @returns {JSX.Element} - A scatter chart displaying event counts over time, with anomalies highlighted. + * + * This component renders a responsive scatter chart using the Recharts library. + * It displays event counts on the Y-axis and timestamps on the X-axis. + * Anomalies, determined by the `isAnomaly` function, are highlighted in red with a larger radius. + */ const AnomalyChart: React.FC = () => { return ( diff --git a/server/controllers/userController.js b/server/controllers/userController.js index c1e1fc1..777a9f4 100644 --- a/server/controllers/userController.js +++ b/server/controllers/userController.js @@ -4,6 +4,28 @@ import { query } from '../models/usersModel.js'; // signup user export default { + /** + * Creates a new user in the database. + * + * This function handles user signup by validating the request data, hashing the password, + * and inserting the user information into the database. If successful, it stores the created + * user in `res.locals.createdUser` for further use in the middleware chain. + * + * Expected request body properties: + * - `username`: The unique username of the new user. + * - `password`: The plaintext password, which will be hashed before storage. + * - `displayName`: The display name of the user. + * - `work_email`: The user’s work email address. + * - `workPhone`: The user’s work phone number. + * + * Error Handling: + * - Responds with a 400 status code if any required field is missing. + * - Responds with a 500 status code if there is a server error during the database operation. + * + * @param {Object} req - The request object containing the user data in `req.body`. + * @param {Object} res - The response object to store `res.locals.createdUser`. + * @param {Function} next - The next middleware function in the Express stack. + */ createUser: async (req, res, next) => { const { username, password, displayName, work_email, workPhone } = req.body; @@ -47,6 +69,31 @@ export default { } }, + /** + * Authenticates a user based on their email/username and password. + * + * This function verifies the user's credentials by checking if the provided + * email/username and password match an existing user in the database. + * If successful, the user information is stored in `res.locals.loggedinuser` for + * further use in the middleware chain. + * + * Expected request body properties: + * - `username`: The username of the user (optional if `work_email` is provided). + * - `work_email`: The user's work email address (optional if `username` is provided). + * - `password`: The plaintext password provided by the user, which is compared with the hashed password in the database. + * + * Edge Cases: + * - If no matching user is found in the database, responds with a 400 status and a "User Does Not Exist" message. + * - If the password does not match, responds with a 400 status and a "Login Unsuccessful" message. + * + * Error Handling: + * - Responds with a 500 status code and logs the error if there is a server error during the database operation. + * + * @param {Object} req - The request object containing user login credentials in `req.body`. + * @param {Object} res - The response object to store `res.locals.loggedinuser` on successful login. + * @param {Function} next - The next middleware function in the Express stack. + * @returns {void} - Calls the next middleware function in the chain. + */ //login user loginUser: async (req, res, next) => { const { username, work_email, password } = req.body; @@ -92,7 +139,32 @@ export default { }); } }, - + /** + * Updates a user's AWS credentials in the database. + * + * This function updates the specified user's AWS credentials in the `users` table, + * including AWS access key, secret access key, and region. It expects the AWS credentials + * to be provided in `res.locals.awsCredentials` and the username in `req.body.username`. + * + * Expected request body properties: + * - `username`: The username of the user whose AWS credentials are being updated. + * + * Expected `res.locals` properties: + * - `awsCredentials.aws_access_key`: The user's AWS access key. + * - `awsCredentials.aws_secret_access_key`: The user's AWS secret access key. + * - `awsCredentials.aws_region`: The AWS region associated with the user's credentials. + * + * Edge Cases: + * - If `username` is not provided in `req.body`, responds with a 400 status and an error message. + * + * Error Handling: + * - Responds with a 500 status code and logs the error if there is an issue updating the database. + * + * @param {Object} req - The request object, containing `username` in `req.body`. + * @param {Object} res - The response object, where `res.locals.updatedUser` will store the updated user record. + * @param {Function} next - The next middleware function in the Express stack. + * @returns {void} - Calls the next middleware function in the chain. + */ saveUserAwsCredentials: async (req, res, next) => { if (!req.body.username) return next({ @@ -132,32 +204,3 @@ export default { } }, }; - -// getAllUsers: async (req, res, next) => { -// try { -// const queryText = 'SELECT * FROM users;'; -// const result = await pool.query(queryText); -// if (result.rows.length === 0) { -// return res.status(404).json({ error: `No User found` }); -// } -// res.status(200).json(result.rows); -// } catch (err) { -// next(err); -// } -// }, - -// getUserByField: async (req, res, next) => { -// const { field, value } = req.query; //used to be req.params -// try { -// const queryText = `SELECT * FROM users WHERE ${field} = $1;`; -// const result = await pool.query(queryText, [value]); -// return res.status(200).json(result.rows[0]); -// } catch (err) { -// next(err); -// } -// }, -// }; - -//example -//getUserByField('username', 'someUsername'); -//getUserByField('work_email', 'someWorkEmail@example.com'); diff --git a/server/models/usersModel.js b/server/models/usersModel.js index b2a7d10..8969249 100644 --- a/server/models/usersModel.js +++ b/server/models/usersModel.js @@ -1,6 +1,15 @@ +// Importing pg (PostgreSQL) module to enable interaction with the database import pg from 'pg'; +// Importing dotenv configuration to load environment variables from .env file import 'dotenv/config'; +/** + * Configures and creates a new PostgreSQL connection pool. + * - Uses `pg.Pool` to manage multiple client connections to the database. + * - Reads host, database, and other credentials based on the environment: + * - `host`: Uses 'trailguide-db-prod' in production and 'trailguide-db-dev' in development. + * - `database`: Reads from `POSTGRES_DB` environment variable, or defaults to 'tgdb-dev'. + */ const pool = new pg.Pool({ user: 'tgadmin', password: 'secret', @@ -12,24 +21,61 @@ const pool = new pg.Pool({ database: process.env.POSTGRES_DB || 'tgdb-dev', }); -// if an error is encountered by a client while it sits idle in the pool -// the pool itself will emit an error event with both the error and -// the client which emitted the original error -// this is a rare occurrence but can happen if there is a network partition -// between your application and the database, the database restarts, etc. -// and so you might want to handle it and at least log it out +/** + * Listens for errors on idle clients in the PostgreSQL connection pool. + * + * This event handler is triggered when a client in the pool encounters an error while idle, + * which can help catch and log issues such as network problems or incorrect configurations + * in the database connection setup. + * Logs the error message and stack trace to aid in diagnosing and resolving issues. + */ pool.on('error', function (err, client) { console.error('idle client error', err.message, err.stack); }); -//export the query method for passing queries to the pool +/** + * Executes a parameterized SQL query on the PostgreSQL database. + * + * This function allows safe execution of SQL queries with dynamic parameters, leveraging + * the connection pool to manage database connections efficiently. + * + * @param {string} text - The SQL query string, which may include placeholders (e.g., `$1`) for parameterized values. + * @param {Array} values - An array of values to replace the placeholders in the SQL query, ensuring safe input handling. + * @returns {Promise} - A promise that resolves with the query result object or rejects with an error if the query fails. + * + * @example + * // Example usage of the query function + * const result = await query('SELECT * FROM users WHERE id = $1', [userId]); + * console.log(result.rows); // Access rows from the result + */ export async function query(text, values) { - // console.log('ipsModel.query:', text.split('\n')[1], values); return pool.query(text, values); } -// the pool also supports checking out a client for -// multiple operations, such as a transaction +/** + * Retrieves a client connection from the PostgreSQL connection pool. + * + * Use this function to obtain a client for executing multiple SQL operations, such as + * in a transaction. Ensure that you release the client back to the pool after completing + * your operations to maintain efficient pool management. + * + * @returns {Promise} - A promise that resolves with a connected client instance + * from the pool. The client should be released after use by calling `client.release()`. + * + * @example + * // Example usage of the connect function for a transaction + * const client = await connect(); + * try { + * await client.query('BEGIN'); + * // Execute multiple queries + * await client.query('COMMIT'); + * } catch (error) { + * await client.query('ROLLBACK'); + * throw error; + * } finally { + * client.release(); // Always release the client back to the pool + * } + */ export async function connect() { return pool.connect(); } diff --git a/server/server.js b/server/server.js index ed6ee18..f499f8c 100644 --- a/server/server.js +++ b/server/server.js @@ -11,21 +11,22 @@ const app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -//signup router +// Route for signing up a new user +// Expects a request body with user details (e.g., username, password, email). +// Calls `userController.createUser` middleware to create a new user in the database. +// Responds with status 201 and the created user information in `res.locals.createdUser`. app.post('/api/signup', userController.createUser, (req, res) => { res.status(201).json(res.locals.createdUser); }); -//login router +// Route for logging in an existing user +// Expects a request body with user login details (e.g., username, password). +// Calls `userController.loginUser` middleware to authenticate the user. +// Responds with status 200 and the logged-in user information in `res.locals.loggedinuser`. app.post('/api/login', userController.loginUser, (req, res) => { res.status(200).json(res.locals.loggedinuser); }); -// route to get all users -// app.get('/api/users', userController.getAllUsers); - -// app.get('/api/user', userController.getUserByField); - app.get( '/events', awsController.getEvents,