Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'docs': Finishes writing documentation Nancy worked on #87

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion client/src/components/charts/AnomalyChart.tsx
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 },
Expand All @@ -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 (
<ResponsiveContainer width="100%" height={300}>
Expand Down
103 changes: 73 additions & 30 deletions server/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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', '[email protected]');
66 changes: 56 additions & 10 deletions server/models/usersModel.js
Original file line number Diff line number Diff line change
@@ -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',
Expand All @@ -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<Object>} - 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<pg.PoolClient>} - 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();
}
15 changes: 8 additions & 7 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading