You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a handy document that tells you where to find what. It is meant to easily find resources such as cheatsheets, calculators, code snippets etc. This is meant to be a living document and should be used with and improved with every project.
Most cheatsheets are stored in the cheat sheets gist. If it not possible to store the file int the gist, it is stored in the OneDrive/Programming/CheatSheets folder. The table below describes the cheat sheets. If you make any changes to cheat sheets, please also remember to update this table.
Doc name
Desription
Location
Format
Deployment CI/CD cheatsheet
General notes on how to deploy. Linode Linux Ubuntu VM deployment
C:\Users\donnp\source\repos
Markdown
Dev best practices
What documents to include in any sw project and how to get started
C:\Users\donnp\source\repos
Markdown
Dev containers cheatsheet
How to set up a dev container for your project
C:\Users\donnp\source\repos
Markdown
Email validation with JWT
Walkthrough of how to create a registration and login system with email verification
C:\Users\donnp\source\repos
Markdown
Git cheatsheet
How to work with git and GitHub
C:\Users\donnp\source\repos
Markdown
HTML cheatsheet
Folder containing various HTML code examples
OneDrive/Programming/CheatSheets
HTML, Markdown
Mermaid cheatsheet
How to use Mermaid to create various types of diagrams in Markdown
I also have a book (yes, real paper) where I practice writing code snippets.
Chunking
Embeddings
Document cleaning (for RAG)
Basic HTML
Penzu
There are some stuff captured in Penzu, but this should all be moved elsewhere. Worth a look though. Penzu
Utility scripts
Check the utilities repo for handy scripts like how to count the number of lines in a file etc.
Secrets and access tokens
You should never store secrets and such in repos on GitHub. I normally store secrets and personal access tokens in a .env file in the repo. You must add this filename to your .gitignore. If you are working on multiple machines, you must manually copy this file (.env) to all the machines, since it obviously won't be included when you clone a repo.
Updates and examples
React Router cheatsheet is outdated. See Peterborough & Fenlands Polyamory website for a newer example.
This document lists some of the best practices to follow when undertaking any software project
General documentation
README.md
What is it? A file providing information about a project for users and developers.
Why do I need it? A README.md helps users and developers understand, use, and contribute to your project.
How do I get started: ChatGPT prompt: Write template text for a README.md file in markdown format
DevLog.md
What is it? Records of every worksession of the developer
Why do I need it? To keep history of what was done, problems experienced and so on.
How do I get started: Copy an example from one of the previous project. See PersonalWebsite for a good example
Note: You can use the "work done" from devlog as comments for git commits.
Requirements.md
What is it? Outlines features and expectations from a project from a user's perspective.
Why do I need it? Defines project features and user expectations for clear development goals and user satisfaction.
How do I get started: ChatGPT prompt: Write template text for a User requirements file in markdown format
Design.md
What is it? A design spec details the visual and technical aspects of a project's development.
Why do I need it? Guides visual and technical aspects, ensuring a cohesive and effective development process.
How do I get started: ChatGPT prompt: Write template text for a Design specification file for a webapp in markdown format
Using the knowledge base
You can use the knowledge base ("Where to find what.md") to search for existing knowledge and code snippets. NB: Remember to update "Where to find what.md" if you add any new resources (repo, cheatsheets, paper notes, Notability etc).
Environment and setup
Before starting to write code, considder the devops requirements and implement as required:
Where will the solution be deployed? Do you need to create infrastructure folder and files?
devcontainer / venv
.github/workflows
What versions of OS and software will you use? Confirm that these will be available in the production environment.
Think about your environmental variables. Will you use .env files or add them via the OS?
Will you need to distinguish between prod and dev environments? Do you need conditional logic to set variables?
Here's a detailed list of steps to create a registration and login system with a React TypeScript frontend, Node/Express backend, and PostgreSQL database.
Before doing this manually, considder forking a scaffold code repo. You can also use this ChatGPT prompt to get you started:
Write all the scaffold code and powershell scripts for a basic web app, following these guidelines: The front end should be make using React. It should have a login/registration functionality. The registration process should use email validation. Authentication should be done using JWT. Add a login success page. All all the necessary jsx and css to make this work. Routes should be placed in a separate folder. The backend should be written in Python using Flask. The database is mongodb. Write a powershell script to add a .devcontainer folder, a .github and a static. Remember to write all the code.
Manual process
Frontend
Set up a new React TypeScript project using Create React App.
Install any necessary dependencies (e.g. axios for making HTTP requests, react-router-dom for handling client-side routing).
Create a basic layout for the registration and login pages using HTML and CSS.
Create a registration form component with fields for name, email, and password.
Add validation to the registration form using a library like Formik or React Hook Form.
Add a login form component with fields for email and password.
Add validation to the login form using a library like Formik or React Hook Form.
Add client-side routing using react-router-dom to handle navigation between the registration and login pages.
Backend
Set up a new Node/Express project.
Install any necessary dependencies (e.g. express for creating an HTTP server, pg for connecting to a PostgreSQL database, bcrypt for hashing passwords).
Create a PostgreSQL database and set up a connection to it using the pg library.
Create a schema for the users table in the database with columns for name, email, password hash, and email validation status.
Create a registration endpoint in the Express server that handles POST requests to create new user accounts. This endpoint should:
Receive the user's registration information (name, email, password).
Check if the email already exists in the database. If it does, return an error response to the client. If it doesn't, continue to the next step.
Hash the user's password using the bcrypt library.
Insert a new row into the users table with the user's information.
Send an email to the user with a validation link.
Create a validation endpoint in the Express server that handles GET requests to validate user email addresses. This endpoint should:
Receive a validation token (e.g. a UUID) in the query string.
Look up the user with the matching validation token in the database.
If a matching user is found, update their email validation status to "validated" and return a success response to the client. If no matching user is found, return an error response.
Create a login endpoint in the Express server that handles POST requests to authenticate user logins. This endpoint should:
Receive the user's email and password.
Look up the user with the matching email in the database.
If a matching user is found, check if the provided password matches the hashed password in the database using the bcrypt library. If the passwords match, return the user's information to the client. If the passwords don't match, return an error response. If no matching user is found, return an error response.
Putting it all together
Update the registration form component in the React app to make a POST request to the registration endpoint on the backend when the user submits the form.
Update the login form component in the React app to make a POST request to the login endpoint on the backend when the user submits the form.
When the user submits the registration form, the backend should create a new user account and send a validation email to the user.
When the user clicks the validation link in the email, the backend should validate the user's email address and update their status in the database.
When the user submits the login form, the backend should authenticate the user's credentials and return their information to the frontend if they are valid.
Use client-side routing in the React app to navigate between the registration and login pages as needed.
Scaffold code
React frontend with Flask backend and mongdb
1. React Frontend:
Firstly, make sure you have Node.js installed, then use create-react-app to generate a new React app:
npx create-react-app your-web-app
cd your-web-app
Now, let's add some React components for login, registration, and a success page. Create files in the src directory:
Login.js:
// src/Login.jsimportReactfrom'react';constLogin=()=>{// Your login component logic here};exportdefaultLogin;
Registration.js:
// src/Registration.jsimportReactfrom'react';constRegistration=()=>{// Your registration component logic here};exportdefaultRegistration;
Success.js:
// src/Success.jsimportReactfrom'react';constSuccess=()=>{// Your success page component logic here};exportdefaultSuccess;
2. Flask Backend:
For the backend, create a virtual environment, install Flask and related packages, and set up your Flask app. Make sure to have MongoDB installed and running.
There you have it, partner! You've got the basic structure for your web app. Now, you'll need to fill in the logic for the components, Flask routes, and connect them with JWT for authentication. Happy trailblazin'!
Using unittest in python, write unit tests for the following function. Assume the function to be tested is located in a file called tpc_bot.py, and is located in the same folder as the unit test file. Remember to import the function from its location.
The Perfect Prompt (GPT-4)
Craft the perfect prompt that instructs you to create an article on 'sustainable living'. The aim of the article is to rank at the top of google.
Critically review your last response. Address any weaknesses and rewrite to be more comprehensive.
What you gave me above is not a prompt. It is a summary of an article. You must provide me with a prompt that I can feed back to you that will cause you to generate a prompt.
The 5 Whys
Use the 5 Whys technique to help me get clarity. Start by asking me what action I want to take and keep asking why until I type OK.
A Room Full of Experts
I have problem/situation XYZ. List the experts most suitable to give advice on this topic.... I want you to roleplay. Act as each of those roles and provide each expert's advice on what to do.
Run as a Model
Run as a model: Book a train ticket online
A Room Full of Wisdom
Roleplay. Become 3 separate characters: Socrates, Einstein and the smartest AI on the planet. Use everything you know about Socrates and Einstein to respond as they may have done. I need to advise on a situation and I want to be guided by all 3 characters.
Creative Thinking
Apply the SCAMPER model to this situation. (or any other relevant model)
Sell like a Pro
(URL) Write a 500 word description for this product page. Make it compelling and appealing to (target audience) who (some attribute). Optimise for the following keywords...
Overcome Any Objection and Sell Anything
Roleplay. Your job is to sell me a (product) andovercome all my objections until I relent. I am a (persona). Your pricing is competitive. (Describe the product). You are free to offer installment plans or anything else that may convince me to buy. Start by asking me if I have considdered your offer of a (product).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWS Lambda: A serverless symphony where your API functions as independent, scalable entities.
Azure Functions: Microsoft's cloud offering for serverless API deployment, allowing you to focus on your code.
Containers:
Docker Containers: Wrap your API in a Docker container for consistency across different environments. Kubernetes can help manage these containers at scale. See the Docker cheatsheet
Platform as a Service (PaaS):
Heroku: A serene platform where you can deploy your API effortlessly, abstracting away infrastructure concerns.
Google App Engine: A platform that scales with your API's demands, allowing you to deploy without managing the underlying infrastructure.
Traditional Servers:
Virtual Private Servers (VPS): Platforms like AWS EC2, DigitalOcean, or Linode offer traditional server deployments. You have more control but also more responsibility for maintenance.
Serverless Frameworks:
Serverless Framework: An enchanting way to deploy APIs on various cloud providers with minimal configuration.
API Gateway Services:
AWS API Gateway: A gateway to connect and deploy APIs with ease, integrating seamlessly with other AWS services.
Google Cloud Endpoints: A service to deploy, monitor, and manage APIs on Google Cloud.
if you get this error: [email protected]: Permission denied (publickey)., run eval `ssh-agent -s` to start the ssh agent (you should get back a process id), then ssh-add ~/.ssh/id_rsa_linode to add the key to the agent.
Try to login again. This time it should work.
Install docker on Ubuntu
Accoring to this YouTube video (I did it this way. I installed from the apt repo and everything worked fine.):
On Google, search for Install Desktop on Ubunt. The first results should be this page
Navigate to the parent directory in which the virtual environment will be located (this is the same as the root directory of the code)
Run python -m venv PFP_env to create the venv (PFP_env is the name of the environment)
Add the PFP_env folder to .gitignore
Activate the venv: PFP_env\Scripts\Activate.ps1 (PowerShell) or source PFP_env/Scripts/activate (gitbash)
confirm flask is installed: flask --version
pip install gunicorn
pip freeze > backend/requirements.txt
Run the app using gunicorn: gunicorn backend/app:app
I got this error: ModuleNotFoundError: No module named 'fcntl'
so I tried pip install fcntl. Got error. Turns out The fcntl module is not available on Windows. So going to switch to venv. That did not solve the problem. Turns out fcntl only exists on Linux so probably need a containter or WSL to run this.
Get app files onto server, dependencies, mongodb setup
Install the Remote Containers extension in VS Code (Looks like this has now been rebranded to Dev Containers)
Ensure that Docker is running by checking for the Docker icon in the system tray or opening up a terminal and running docker version.
If docker is not running, launch it from the start menu.
Open or clone a project from GitHub.
Use the command pallete (Ctrl + Shift + P) to add a dev container to the project. Enter add dev and select Dev Containters: Add Dev Container Configuration files.
You can use the ChatGPT prompt below to create a docker file for the dev container. Remember to run pip freeze (if working in python) to get a list of Python dependencies and put them in a requirements.txt file
*Write a docker file for a project with the following information:
The project consists of a Flask backend and a React frontend
The this docker file is used for development, not production
The command for starting the backend server is py backend/app.py
The command for starting the frontend server is npm start
The backend uses Python 3.11.5
The file structure is as follows (only showing the most relevant files and folders):
root
|-backend
|- app.py
|- requirements.txt
|- src
|- App.js
|- public
|- index.html
|- node_modules
|- package-lock.json
|- package.json*
This assumes your React app is a standard create-react-app structure. Adjustments might be needed based on your project structure and dependencies.
# Use an official Node runtime as a parent imageFROM node:14
# Set the working directory in the containerWORKDIR /usr/src/app
# Copy package.json and package-lock.json to the working directoryCOPY package*.json ./
# Install app dependenciesRUN npm install
# Copy the local source files to the working directoryCOPY . .
# Build the appRUN npm run build
# Expose the port that the app will run onEXPOSE 3000
# Define environment variableENV REACT_APP_API_URL=http://api.example.com
# Command to run the applicationCMD ["npm", "start"]
This Dockerfile does the following:
Uses the official Node.js 14 image as a base.
Sets the working directory inside the container.
Copies package.json and package-lock.json into the container and installs the dependencies.
Copies the rest of the application code into the container.
Builds the React app using npm run build.
Exposes port 3000 (assuming your React app is set up to run on this port).
Defines an environment variable (REACT_APP_API_URL in this case, adjust as needed).
Specifies the command to run when the container starts (npm start).
To build and run your Docker image, navigate to the directory containing your Dockerfile and run:
docker build -t your-image-name .
docker run -p 3000:3000 your-image-name
Replace your-image-name with a name for your Docker image. The -p 3000:3000 option maps port 3000 from the container to port 3000 on your host machine. Adjust the port mapping if your React app runs on a different port.
An existing user can reset password (if forgotten)
High level process
User registers by entering email and password
After validation, an email is sent to the user
User has to click on the link in the email to verify email address
User is navigated to a page that tells him to check his email for the verification email
If user tries to log on before verifying email, he is directed to a page that asks him to first validate email address
Once the email is verified, user can log in and get access to services
Here is the detailed flow diagram:
flowchart TD;
A --> B
B --> C
C --> |Yes|D
C --> |No|B
D --> |Yes|F
D --> |No|E
F --> B
E --> G
G --> H
H --> I
I --> |Yes|J
I --> |No|N
J --> K
K --> |Yes|L
K --> |No|F
L --> M
M --> N
N --> O
O --> |Yes|P
O --> |No|N
P --> |Yes|Q
P --> |No|S
Q --> |Yes|R
Q --> |No|S
R --> |Yes|T
R --> |No|H
S --> N
A((Start))
B(User enters email and password in registration form and submits)
C{Email and pw OK?}
D{Email already exists in db?}
E(Create new user in db, emailVerified = False)
F(Return and display error)
G(Send verification email)
H(Redirect user to Check your email page)
I{User clicks verification link in email?}
J(Handle verification request)
K{Verification OK?}
L(Set emailVerified = True)
M(Redirect user to login page)
N(User enters email and password in login form and submits)
O{Email and pw OK?}
P{Email already exists in db?}
Q{Password correct?}
R{Email verified?}
S(Return and display error)
T((User logged in successfully))
sequenceDiagram
autonumber
User->>Frontend: Enter email and password
activate User
activate Frontend
Frontend->>Backend: Send email and password
activate Backend
Backend ->> Database: Check if email already exists
activate Database
Database -->> Backend: Email doesn't exist (is new)
Backend ->> UserEmail: Send verification email
activate UserEmail
Backend -->> Frontend: Redirect user to Check email page
User ->> UserEmail:Click on verification link in email
UserEmail -->> Backend: Handle verification request
deactivate UserEmail
Backend -->> Frontend: Redirect user to login page
User ->> Frontend: Enter email and password
Frontend->>Backend: Send email and password
Backend ->> Database: Authentication request
Database -->> Backend: Authenticated
deactivate Database
Backend -->> Frontend: Redirect to Login successful page
User ->> Frontend: Do something
deactivate Frontend
deactivate User
deactivate Backend
Loading
Work Breakdown Structure (WBS)
mindmap
Project scope
Build registration functionality
Complete frontend work
Create link on homepage to Registration page
Build Registration page
Build form to capture valid email and password
Build button to send email and pw to backend
Build "Check your email" page
Complete backend work
Create register endpoint
Write logic to check if email exists
Write logic to save email and pw to db
Write logic to send verification email
Write logic to redirect user to Check email page
Create verification endpoint
Write logic to handle verification
Write logic to redirect to login page
Login functionality
Frontend work
Home page
Create link to login page
Login page
Build form to capture valid email and password
build button to send email and pw to backend
Backend work
Create login endpoint
Write logic to Autenticate user
Write logic to return jwt token
Write logic to redirect to Login successful page
Common elements
Database work
Build user table
Write stored procedure - check if user exists
Excluded scope - Prerequisites
Home page with Nav bar
Loading
Funtional Decomposition Diagram
flowchart TD
a --> j
a --> b
b --> c
b --> d
b --> n
c ---> e
c --> f
c --> g
d ---> h
d ---> i
d -.-> g
j --> k
k --> l
d --> m
n ---> o
n ---> p
n ---> q
a[System]
b[Sign in services]
c[Login]
d[Register]
e[Login page]
f[login endpoint]
g[user table]
h[Register page]
i[register endpoint]
j[Prerequisites]
k[Home page]
l[Nav bar]
m[check email endpoint]
n[Reset password]
o[Forgot password page]
p[reset-password endpoint]
q[new password page]
Loading
Approach
We will use the NodeMailer library in javascript to do this. For creating temporary email addresses, we use 10minutemail.com.
Similar components can be created for login, email verification, and protected content. TODO: Write out these forms.
Set Up Routes:
Configure routes using react-router-dom in the App.js file.
// src/App.js
//Note: this way of doing routers is out of date. You should update this.
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import RegisterForm from './components/RegisterForm';
const App = () => {
return (
<Router>
<Switch>
<Route path="/register" component={RegisterForm} />
{/* Add routes for login, email verification, and protected content */}
</Switch>
</Router>
);
};
export default App;
Backend (Node.js with Express)
Set Up Node.js Project:
Create a new Node.js project and install the necessary dependencies.
Create a file named app.js and set up your Express application.
// app.js
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const nodemailer = require('nodemailer');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
mongoose.connect('mongodb://localhost:27017/usersdb', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// Define User schema and model using Mongoose
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
isVerified: { type: Boolean, default: false },
});
const User = mongoose.model('User', userSchema);
// Set up bcrypt for password hashing
const saltRounds = 10;
// Set up JWT secret key
const jwtSecretKey = 'your_jwt_secret_key';
// Set up Nodemailer for sending verification emails
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '[email protected]', // replace with your email
pass: 'your_email_password', // replace with your email password
},
});
// Express routes
app.post('/api/register', async (req, res) => {
try {
const { email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, saltRounds);
const newUser = new User({ email, password: hashedPassword });
await newUser.save();
// Send verification email
const token = jwt.sign({ email: newUser.email }, jwtSecretKey, { expiresIn: '1h' });
const verificationLink = `http://localhost:3000/verify-email?token=${token}`;
const mailOptions = {
from: '[email protected]',
to: newUser.email,
subject: 'Email Verification',
text: `Click the following link to verify your email: ${verificationLink}`,
};
await transporter.sendMail(mailOptions);
res.json({ message: 'Registration successful! Check your email for verification.' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
});
app.get('/api/verify-email', async (req, res) => {
try {
const token = req.query.token;
const decoded = jwt.verify(token, jwtSecretKey);
const user = await User.findOne({ email: decoded.email });
if (user) {
user.isVerified = true;
await user.save();
res.redirect('http://localhost:3000/email-verified');
} else {
res.status(404).json({ message: 'User not found' });
}
} catch (error) {
console.error(error);
res.status(401).json({ message: 'Invalid token' });
}
});
// Set up login route and protected routes similarly
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Replace the placeholders such as 'your_jwt_secret_key', '[email protected]', and 'your_email_password' with your actual values. Also, adjust the frontend routes and components accordingly.
Now, you have a basic setup for a web app with user registration, email verification, and login using React for the frontend and Node.js with Express for the backend. This is a simplified example, and you may need to add more features, error handling, and security measures for a production environment.
Functional Decomposition Diagram for Registration/Login system with email validation
flowchart LR;
A --> B
A --> C
B --> D
B --> E
B --> V
C --> R
C --> S
D --> F
D --> K
D --> N
E --> G
E --> U
I --> T
L --> M
R --> H
R --> I
R --> J
R --> L
S --> O
S --> P
S --> Q
K -.- U
F -.- G
H -.- O
M -.- T
A[System]
B[Frontend]
C[Auth server]
D[Registration page]
E[Login page]
F[Registration Email & pw validation]
G[Login Email & pw validation]
H[Check if email exists]
I[Create new user]
J[Send verification email]
K[Redirect user to Check email page]
L[Handle verification request]
M[Set emailVerified = True]
N[Redirect user to login page]
O[Check if email exists]
P[Check if pw correct]
Q[Check if email verified]
R[Registration functions]
S[Login functions]
T[Set emailVerified = False]
U[Redirect user to Check email page]
V[Check email page]
Loading
Backend (Flask)
Install Dependencies:
Install necessary packages for Flask, Flask-Bcrypt, Flask-Mail, and Flask-JWT-Extended.
Create a file named app.py and set up your Flask application.
# app.py
from flask import Flask, request, jsonify, redirect
from flask_bcrypt import Bcrypt
from flask_mail import Mail, Message
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
from flask_cors import CORS
import jwt
app = Flask(__name__)
CORS(app)
app.config['SECRET_KEY'] = 'your_jwt_secret_key'
app.config['MAIL_SERVER'] = 'smtp.gmail.com' # Use your email provider's SMTP server
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USE_SSL'] = False
app.config['MAIL_USERNAME'] = '[email protected]' # Replace with your email
app.config['MAIL_PASSWORD'] = 'your_email_password' # Replace with your email password
app.config['MAIL_DEFAULT_SENDER'] = '[email protected]'
mail = Mail(app)
bcrypt = Bcrypt(app)
jwt = JWTManager(app)
# Simulated user database (replace with a real database)
users = []
# Route to register a new user
@app.route('/api/register', methods=['POST'])
def register():
data = request.get_json()
# Check if the user already exists
if any(user['email'] == data['email'] for user in users):
return jsonify({'message': 'Email already registered'}), 400
hashed_password = bcrypt.generate_password_hash(data['password']).decode('utf-8')
new_user = {'email': data['email'], 'password': hashed_password, 'is_verified': False}
users.append(new_user)
# Send verification email
token = jwt.encode({'email': new_user['email']}, app.config['SECRET_KEY'], algorithm='HS256').decode('utf-8')
verification_link = f'http://localhost:5000/api/verify-email?token={token}'
msg = Message('Email Verification', recipients=[new_user['email']])
msg.body = f'Click the following link to verify your email: {verification_link}'
mail.send(msg)
return jsonify({'message': 'Registration successful! Check your email for verification.'})
# Route to verify email
@app.route('/api/verify-email', methods=['GET'])
def verify_email():
token = request.args.get('token')
try:
decoded = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
user = next((u for u in users if u['email'] == decoded['email']), None)
if user:
user['is_verified'] = True
return redirect('http://localhost:3000/email-verified')
else:
return jsonify({'message': 'User not found'}), 404
except jwt.ExpiredSignatureError:
return jsonify({'message': 'Token has expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'message': 'Invalid token'}), 401
# Route to log in
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
user = next((u for u in users if u['email'] == data['email']), None)
if user and bcrypt.check_password_hash(user['password'], data['password']):
if user['is_verified']:
access_token = create_access_token(identity={'email': user['email']})
return jsonify({'access_token': access_token})
else:
return jsonify({'message': 'Email not verified. Please check your email for verification.'}), 401
else:
return jsonify({'message': 'Invalid credentials'}), 401
# Protected route
@app.route('/api/protected', methods=['GET'])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
if __name__ == '__main__':
app.run(debug=True)
Replace placeholders such as 'your_jwt_secret_key', '[email protected]', and 'your_email_password' with your actual values.
Run Your Flask App:
Run your Flask app.
python app.py
Comparison
For comparison, here is login code without email validation:
Front end
Set Up React App:
Create a new React app using Create React App or your preferred method.
npx create-react-app react-authentication
cd react-authentication
Create Components:
Create the necessary components for registration and login. You might want to create components like RegistrationForm, LoginForm, and App for the overall structure.
Implement email validation logic in the registration form. You can use regular expressions or a validation library like Yup.
npm install yup
import * as Yup from 'yup';
// ... (previous imports)
const RegistrationForm = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const validationSchema = Yup.object().shape({
email: Yup.string().email('Invalid email').required('Email is required'),
password: Yup.string().required('Password is required'),
});
const handleRegistration = () => {
validationSchema.validate({ email, password }).then(() => {
// Proceed with registration logic - see below
}).catch(error => {
// Handle validation errors
console.error(error.message);
});
};
// ... (rest of the component)
};
export default RegistrationForm;
Connect to Backend:
Connect your registration and login forms to a backend server for authentication and user management. You could use libraries like Axios to make HTTP requests.
npm install axios
Update your registration and login logic to communicate with the backend.
This example uses Express for handling HTTP requests, Mongoose for MongoDB interactions, Bcrypt for password hashing, and JSON Web Tokens (JWT) for authentication.
Set Up Your Node.js Project:
Create a new Node.js project and install the necessary dependencies.
Create a file named app.js and set up your Express application.
// app.js
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const app = express();
app.use(express.json());
mongoose.connect('mongodb://localhost:27017/usersdb', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// Define User schema and model using Mongoose
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
});
const User = mongoose.model('User', userSchema);
// Set up bcrypt for password hashing
const saltRounds = 10;
// Set up JWT secret key
const jwtSecretKey = 'your_jwt_secret_key';
// Express routes
app.post('/api/register', async (req, res) => {
try {
const { email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, saltRounds);
const newUser = new User({ email, password: hashedPassword });
await newUser.save();
res.json({ message: 'User registered successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
});
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (user && (await bcrypt.compare(password, user.password))) {
const token = jwt.sign({ email: user.email }, jwtSecretKey);
res.json({ access_token: token });
} else {
res.status(401).json({ message: 'Invalid credentials' });
}
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Internal Server Error' });
}
});
// Set up a protected route
app.get('/api/protected', verifyToken, (req, res) => {
res.json({ message: 'You have access to this protected route' });
});
function verifyToken(req, res, next) {
const token = req.headers['authorization'];
if (!token) {
return res.status(403).json({ message: 'Token not provided' });
}
jwt.verify(token, jwtSecretKey, (err, decoded) => {
if (err) {
return res.status(401).json({ message: 'Failed to authenticate token' });
}
req.user = decoded;
next();
});
}
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Run Your Node.js App:
Start your Node.js app.
node app.js
Now, your Node.js backend is set up to handle user registration, login, and a protected route using MongoDB as the user database. Please replace 'your_jwt_secret_key' with a secure key for production use. Also, ensure you have a running MongoDB instance and update the MongoDB URI accordingly.
Backend option 2: Flask
Install Flask and Flask-CORS:
Install Flask and Flask-CORS for handling Cross-Origin Resource Sharing (CORS) to allow requests from your React frontend.
pip install Flask Flask-CORS
Initialize Flask App:
Create a file named app.py and initialize your Flask app.
# app.py
from flask import Flask, jsonify, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
if __name__ == "__main__":
app.run(debug=True)
Option 1: Set Up SQLite Database:
Create SQListe db
Create a simple SQLite database to store user information.
# app.py (add to the existing file)
from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
Create Registration Endpoint:
Add a route to handle user registration.
# app.py (add to the existing file)
from flask_bcrypt import Bcrypt
bcrypt = Bcrypt(app)
@app.route('/api/register', methods=['POST'])
def register():
data = request.get_json()
hashed_password = bcrypt.generate_password_hash(data['password']).decode('utf-8')
new_user = User(email=data['email'], password=hashed_password)
db.session.add(new_user)
db.session.commit()
return jsonify({'message': 'User registered successfully'})
Create Login Endpoint:
Implement a route to handle user login.
# app.py (add to the existing file)
from flask_jwt_extended import JWTManager, create_access_token, jwt_required
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key'
jwt = JWTManager(app)
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(email=data['email']).first()
if user and bcrypt.check_password_hash(user.password, data['password']):
access_token = create_access_token(identity={'email': user.email})
return jsonify({'access_token': access_token})
else:
return jsonify({'message': 'Invalid credentials'}), 401
Option 2: Set Up MongoDB Database:
Install Flask-PyMongo
Install Flask-PyMongo to integrate Flask with MongoDB.
pip install Flask-PyMongo
Initialize Flask App with MongoDB:
Update your app.py to include the Flask-PyMongo configuration.
# app.py
from flask import Flask, jsonify, request
from flask_cors import CORS
from flask_pymongo import PyMongo
app = Flask(__name__)
CORS(app) # Enable CORS for all routes
app.config['MONGO_URI'] = 'mongodb://localhost:27017/usersdb' # Replace with your MongoDB URI
mongo = PyMongo(app)
Create Registration Endpoint with MongoDB:
Modify the registration endpoint to use MongoDB for storing user information.
# app.py (add to the existing file)
from flask_bcrypt import Bcrypt
bcrypt = Bcrypt(app)
@app.route('/api/register', methods=['POST'])
def register():
data = request.get_json()
hashed_password = bcrypt.generate_password_hash(data['password']).decode('utf-8')
users_collection = mongo.db.users
new_user = {'email': data['email'], 'password': hashed_password}
users_collection.insert_one(new_user)
return jsonify({'message': 'User registered successfully'})
Create Login Endpoint with MongoDB:
Update the login endpoint to interact with MongoDB.
# app.py (add to the existing file)
from flask_jwt_extended import JWTManager, create_access_token, jwt_required
app.config['JWT_SECRET_KEY'] = 'your_jwt_secret_key'
jwt = JWTManager(app)
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
users_collection = mongo.db.users
user = users_collection.find_one({'email': data['email']})
if user and bcrypt.check_password_hash(user['password'], data['password']):
access_token = create_access_token(identity={'email': user['email']})
return jsonify({'access_token': access_token})
else:
return jsonify({'message': 'Invalid credentials'}), 401
Protect Endpoints with JWT:
Use the @jwt_required decorator to protect endpoints that require authentication.
# app.py (add to the existing file)
@app.route('/api/protected', methods=['GET'])
@jwt_required()
def protected():
current_user = get_jwt_identity()
return jsonify(logged_in_as=current_user), 200
Run the Flask App:
Run your Flask app.
python app.py
Now, your Flask backend is set up to handle user registration, login, and protected routes using MongoDB as the user database. Ensure that you have a running MongoDB instance, and update the MongoDB URI in the app.config['MONGO_URI'] accordingly. Also, replace 'your_jwt_secret_key' with a secure key for production use.
Clone the repo to the local machine
Before doing this, the destination folder must be empty
git clone http.... repo name (get link from Github)
To paste in git bash: Insert
Work on the the project on the local machine
Add changed files to the staging area with git add .
Commit to the local repo with git commit -m "<commit message here>"
Push to Github with git push
For more see IFS L1T23 - Version Control II_ Git Basics.pdf in H/L1/T23.
Basic git commands:
Initialise repo on local machine: git init
Check git status: git status
Example of how to commit: git commit -m "message here"
The -m flag is for message
To view change history: git log
To create a branch: git branch my-new-branch-name
To switch branch: git checkout my-branch-name
To stash changes: git stash
To restore a stash: git stash pop
To merge a branch:
First switch back to master: git checkout master
Then merge: git merge my-branch
To link local repo to online repo:
Create repo on local machine
Create new online repo on Github
Link local and remote repos:
git remote add [shortname] [url]
eg: git remote add task4 https...
Push local to remote: git push [remote-name] [branch-name]
eg: git push -u task4 master
The -u flag:
--set-upstream: add upstream (tracking) reference
Short syntax: git push -u origin master
Note: the remote is usually called 'origin' and the main branch is usually called 'master'
In this context 'upstream' refers to the remote repo. Setting the upstream means linking the local repo to the remote repo.
To delete a branch: first switch to another branch
git checkout maingit branch -D branchname (delete locally)
git push origin --delete branchname (delete remote)
To create a branch and switch in one step:
git checkout -b branchName
To push new branch to github:
git push origin head
To merge a branch into the master branch:
git checkout main (switch into the master branch)
git merge branchNamegit push
To discard changes on a branch:
git checkout BranchWithChangesToDiscard
git fetch (make sure this branch is up to date with remote)
git reset --hard origin/main (drop all changes on the current branch and make it point to main)
git push --force-with-lease (to push changes to remote. The --force-with-lease flag is used to force push the changes, as the branch history has been rewritten. However, it also ensures that you don't accidentally overwrite any changes made to the branch by other contributors.)
A pull request is a request to merge a feature branch with the main branch.
before doing the pull request, ensure that your feature branch is pushed to github
On github, go to the repo on which you want to do the merge
Select the Pull Requests tab and select the New pull request (green button)
Select the two brances to be merged (typically main and feature branches)
Give the merge request a name and description. then select create pull request
Once the requested is created, you can review the code if you wish. Once satisfied, merge the pull request (green button).
I prefer to squash the merge request. This combines all the commits into one before merging.
You can also perform the merge from the commandline as described in the brancing section above.
Once the merge is complete, the feature branch is no longer needed, so you can delete it if you want.
Back on your local machine, remember to switch back to main.
Other git commands
To pull the latest version of code from a remote repo and merge with the local repo: git pull. You can also use git fetch, but that will only download the changes without merging them (fetch + merge == pull).
To discard changes that have not yet been staged:
git restore <file>
To unstage all changes: git reset
git statusgit log --oneline
To see the difference between two branches: git diff branch1 branch2
to escape out of a git diff: q + enter
To generate a Google Analytics tracking code for your website, follow these steps:
Sign in to Google Analytics:
If you don't have a Google Analytics account, you'll need to create one. Visit the Google Analytics website and sign in with your Google account.
Create a new property:
Once you're logged in, click on the "Admin" tab at the bottom left of the page.
In the "Property" column, click on the drop-down menu and select "Create Property."
Follow the prompts to set up a new property for your website. Enter the necessary information, such as the website name, URL, and industry category.
Configure your reporting time zone and currency:
In the same process of creating a new property, you'll be prompted to set your reporting time zone and currency. Choose the appropriate options for your website.
Accept the terms of service:
Read and accept the terms of service for Google Analytics.
Get your tracking code:
After creating the property, you'll be taken to the property settings page. Look for the "Tracking Info" tab in the middle column.
Under "Tracking Info," click on "Tracking Code."
Copy the tracking code:
You'll see a block of JavaScript code. This code includes your unique tracking ID and should be added to every page on your website that you want to track.
Copy the entire tracking code.
Add the tracking code to your website:
Paste the tracking code into the HTML of each page on your website, just before the closing tag. If you're using a content management system (CMS) like WordPress, there may be a dedicated section to insert your Google Analytics tracking code.
Check if it's working:
After adding the tracking code, go back to the Google Analytics dashboard and check the "Realtime" reports to see if your data is being tracked.
That's it! Your website is now set up to be tracked by Google Analytics. Keep in mind that it may take some time for data to start appearing in your reports, especially if your website has low traffic initially.
Install Markdown Preview Mermaid Support plugin by Mat Bierner in VS Code.
Close and reopen md file.
Notice to users of your documentation
Paste this notice into your md file if you are using Mermaid:
Note:To view the diagrams in this file, you must install the Markdown Preview Mermaid Support plugin by Mat Bierner in VS Code. Then close and reopen the md file. Documentation here.
Examples
You can create many types of diagrams. These are only the most common types.
sequenceDiagram
autonumber
Alice->>Bob: Hello Bob, how are you?
activate Bob
Bob-->>Alice: I'm good, thanks!
deactivate Bob
Loading
Class Diagram
classDiagram
class Order {
OrderStatus status
int orderId
}
class OrderStatus {
<<enumeration>>
FAILED
PENDING
PAID
}
class PaymentProcessor {
<<interface>>
-string apiKey
#connect(string url, JSON header)
+processPayment(Order order) OrderStatus
}
class Customer {
string name
}
Customer <|-- BusinessCustomer
Customer <-- PrivateCustomer
Order o-- Customer
Order *-- OrderStatus
Loading
---
title: Animal example title
---
classDiagram
note "From Duck till Zebra"
Animal <|-- Duck
note for Duck "can fly\ncan swim\ncan dive\ncan help in debugging"
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
erDiagram
Customer {
string name
string surname
}
Customer ||--o{ Order : places
Customer ||--|{ Address : lives-at
Loading
Gantt Chart
gantt
title A Gantt Diagram
section Section
A task :a1, 2023-01-01, 30d
Another task :after a1 , 20d
section Another
Task in sec :2023-03-12 , 12d
another task : 24d
Loading
Pie Chart
pie
title Key Components
"Component 1" : 30
"Component 2" : 20
"Component 3" : 50
Loading
Notes
Currently printing Mermaid to pdf is not supported in VS Code. You can paste your code in https://mermaid.live/ and create pdfs there.
Formatting and spacing matters. You have to start with ````mermaid (on one line)
and end with ``` (no indentation)
Create new database or switch to other db:
use <dbName>
List all dbs in cluster:
show dbs
Show collections in currently selected db:
show collections
Check the name of the currently selected db:
db
Delete the currently selected db:
db.dropDatabase();
CRUD operations (these commands can be used directly in the console)
Create
To insert a single document in a collection:
db.<collectionName>.insertOne({name: 'Sue', age: 33});
To insert multiple documents in a collection:
db.<collectionName>.insertMany([{name: 'Sue', age: 33}, {name: 'Bob', age: 20}]);
Read
To set format to pretty:
db.test_collection.find().pretty();
To find one record:
db.test_collection.find({name: 'Sue'});
To find the first matching record:
db.test_collection.findOne({name: 'Sue'});
To find all records in a collectio:
db.test_collection.find();
To find one record, but not display all the info:
db.test_collection.find({name: 'Sue'}, {_id: false, age: true});
Update
To update one or more records (updates all fields):
db.test_collection.update({name:'Sue'}, {age:34});
To update one or more records (updates only specified fields):
db.test_collection.update({name:'Sue'}, {$set: {age:34}});
or: db.people.update({name: 'Sue'}, {$set: {name: 'Susan'}}, {multi: true})
In latest version, can also use updateOne() and updateMany()
Delete
Delete all documents in a collection:
db.test_collection.remove();
Delete all mathcing documents in a collection:
db.test_collection.remove({name: 'Susan'});
Delete first mathcing document in a collection:
db.test_collection.remove({name: 'Susan'}, true);
In latest version, can also use deleteOne() and deleteMany()
db.capstones.insertOne({name:'GitHub custom interface', description:'React/Express app that integrates with GitHub API', createDate:'May 12, 2021', gitHubLink:'https://github.com/donnpie/github-custom-interface', estimatedHours:32});
db.capstones.insertOne({name:'Quick Food order system', description:'Java/SQL Server app that manages food orders for delivery business', createDate:'February 24, 2021', gitHubLink:'https://github.com/donnpie/QuickFoodOrderSystem', estimatedHours:40});
db.capstones.insertOne({name:'Maze generator', description:'This simple program generates a maze using an iterative back tracking algorithm, using only vanilla JavaScript', createDate:'February 25, 2021', gitHubLink:'https://github.com/donnpie/Maze-generator', estimatedHours:8});
db.capstones.insertOne({name:'First website', description:'My first attempt at building a basic website', createDate:'January 28, 2021', gitHubLink:'https://github.com/donnpie/FirstWebsite', estimatedHours:16});
db.capstones.insertOne({name:'Mongo Setup', description:' Getting to grips with Mongo admin', createDate:'May 19, 2021', gitHubLink:'null', estimatedHours:3}});
db.capstones.update({name:"Mongo Setup"},{$set: {description: 'Getting to grips with Mongo admin including Mongo Shell usage'}});
In Neo4j's Cypher query language, the dollar sign ($) is used to denote a parameter. Parameters are placeholders that can be replaced with actual values when the query is executed.
Create and edit stuff
Create standalone node
create(n) - create a blank node
Create(n:Person) - create node of type Person
Create(n:Person{name:'Chris'}) - create node with type and property
Create(n:Note{name:'Passive income', text:'To escape the rat race, you have to create sources of passive income.', date:'2024/04/28', type:'permanent'})
Match(s:School), (p:Person) Where s.name = 'ABC' AND p.name = 'Chris' Create (p) - [stu:Studied_At]->(s)
Match(p1:Person), (p2:Person) Where p1.name = 'Chris' AND p2.name = 'Paul' Create (p1)-[f:Friends_with]->(p2)
Add a new property to an existing node
WHERE n.property = $value
SET n.newProperty = $newValue
Rename a property
MATCH (n:Label)
SET n.newProperty = n.oldProperty
// Step 2: Remove the old property
REMOVE n.oldProperty
// Step 3: Create any indexes or constraints on the new property
CREATE INDEX ON :Label(newProperty)
Rename a relationship (Error)
SET oldRelationship:NEW_TYPE
REMOVE oldRelationship:OLD_TYPE
RETURN oldRelationship
or
// Create the new relationship
MATCH (n1)-[oldRel:IS_ANSWERED_BY]->(n2)
Create (n1)-[newRel:Is_followed_by]->(n2)
return n1, n2, oldRel, newRel
// Remove the old relationship
MATCH (n1)-[oldRel:IS_ANSWERED_BY]->(n2)
delete oldRel
return n1, n2, oldRel //Only returns the nodes
Change a property to lowercase
SET n.property = LOWER(n.property)
Queries
Match(n) Return(n)
Match(n:Person) return(n) - Persons only
Match(n:Person) return(n) Limit(1) - Limit number of results
Match(s:School), (p:Person) Where s.name = 'ABC' AND p.name = 'Chris' Return s, p
MATCH (n1:NodeType)-[r]->(n2:NodeType) RETURN n1, r, n2
Find a node by its internal id:
WHERE ID(n) = 13
RETURN n
The function id() is deprecated. Use the function elementId() instead.
find all nodes with no incoming edges (root nodes)
MATCH (n) WHERE NOT ()-->(n) RETURN n
find all nodes with no outgoing edges (leaf nodes)
MATCH (n) WHERE NOT (n)-->() RETURN n
find all downstream edges and nodes of a given node
WHERE startNode.id = $startNodeId
RETURN p
find all upstream edges and nodes of a given node
MATCH p=(upstreamNode)-[*]->(givenNode)
WHERE givenNode.id = $givenNodeId
RETURN p
find all circular paths
RETURN path
Find all nodes with at least one child node
RETURN n, r
Return all ids:
WHERE n.id IS NOT NULL
RETURN DISTINCT "node" as entity, n.id AS id LIMIT 25
UNION ALL
MATCH ()-[r]-()
WHERE r.id IS NOT NULL
RETURN DISTINCT "relationship" AS entity, r.id AS id LIMIT 25;
Find a substring within a property
WHERE n.property CONTAINS 'substring'
RETURN n
Delete
Note: cannot delete a node with relationships. must first delete the relationships
Delete a note
Match(n) Delete(n) - delete matching nodes
Match(n) Detach Delete(n) - Remove relationships and delete
Delete a relationship
MATCH (n1)-[r]->(n2) WHERE ID(n1) = $node1_id AND ID(n2) = $node2_id DELETE rThe function id() is deprecated. Use the function elementId() instead.
How the network stuff works with all the port numbers and what not
Analogies for IP addresses and port numbers
Think of a computer as a block of flats. The IP address is like the street address. It brings you to the front door of the block of flats. Then the port number is the door number. Each door has a unique number. Inside some flats (not all) lives a program. If you want to talk to a specific program you need to know the street address (IP address) to get to the right block of flats. You also need the door number (port number) to get to the right door.
You can think of HTTP and HTTPS as a courier sending messages between different programs living in different blocks of flats and behind different doors. Let's pretend we are looking at communication between two programs. The first program is called the client and it lives in building A, door 1. The second program is called the server and it lives in building B, door 2. The clients wants to ask the server a question. So the client writes a letter and puts it in an envelope. On the front of the envelope the clients puts the server's address details (building B, door 1). On the back of the envelope the client puts his own address details (building A, door 1) and gives it to the courier (a protocol, such as HTTP or HTTPS). The courier knows the city very well. He reads the address on the front of the envelope and then proceeds to that address and delivers the letter to the correct building and door. The server reads the messages and prepares a response in the form of a letter. He puts the letter in an envelope and on the front of the Envelope he writes the client's address details. At the back he writes his own address, so that the client can know the message is from him. He then gives the message to the courier who then delivers it to the client. The client then reads the messages and acts on the information received.
So, to summarise, to send and receive messages between a client and a server, you need a source address (IP and port), and destination address (destination IP and port), a courier (HTTP, HTTPS or somethings else). This combination of source IP address and port and destination IP address and port is known as a web socket.
It is clear to me how the message gets from client to server, but not how it gets back
Some ChatGPT stuff to be cleaned up
There is a problem with your story. When the client writes the letter to the server, he actually doesn't have the server's address. He only has the proxy's address. The proxy has to examine where the message came from and what type of message it is, to determine where to send it.
ChatGPT
You're absolutely right, and I appreciate your keen observation. Let's enhance the analogy to better capture this crucial detail:
Picture our city again, with different buildings representing servers and doors representing programs. The client resides in Building A, Door 1, and the server is in Building B, Door 2. Now, introduce a central information hub, the City Information Center, acting as the reverse proxy.
The client, wanting to communicate with the server, writes a letter and addresses it to the City Information Center (the reverse proxy), indicating that it wants to reach Building B, Door 2. The client doesn't know the server's exact address but trusts the City Information Center to handle the redirection.
The client places its return address (Building A, Door 1) on the back of the envelope and hands it to the courier, which is now the reverse proxy. The reverse proxy, being well-versed in the city's layout, examines the message, notes the sender's address (Building A, Door 1), and determines the appropriate destination based on predefined rules.
Understanding the type of message and where it came from, the reverse proxy redirects the letter to the correct building and door, which is Building B, Door 2 in our example. The server, upon receiving the letter, responds by placing its own return address (Building B, Door 2) on the envelope.
The reverse proxy, equipped with the knowledge of the original sender (Building A, Door 1), ensures that the response reaches the correct destination. This way, the client interacts with the server indirectly through the intermediary of the reverse proxy, which cleverly manages the routing based on its understanding of the city's infrastructure and the characteristics of the messages it handles.
User
Your story doesn't adequately explain how how the reverse proxy knows how to distinguish between multiple messages (from different clients) to the same server
ChatGPT
Let's refine the analogy to address this aspect:
Imagine our city with various buildings (servers) and doors (programs). We have the City Information Center as our reverse proxy, proficient in managing messages. Now, each client lives in a distinct neighborhood and communicates with the reverse proxy using a special language.
When a client, residing in Neighborhood A, wants to send a message to the server in Building B, Door 2, it writes the message in its unique language and addresses it to the City Information Center. The reverse proxy, being multilingual, understands the various languages spoken by the neighborhoods.
The client places its return address (Neighborhood A, Door 1) on the back of the envelope, and the reverse proxy, upon receiving the message, deciphers the language. It notes the sender's neighborhood (Neighborhood A) and identifies the intended recipient (Building B, Door 2).
This clever reverse proxy keeps a mental map of ongoing conversations. When another client from Neighborhood C sends a message to the same server, the reverse proxy discerns the language (Neighborhood C's unique dialect), notes the sender's address (Neighborhood C, Door 3), and ensures it reaches the correct destination (Building B, Door 2).
In this way, the reverse proxy, equipped with linguistic prowess, distinguishes between messages from different clients, directing them to the appropriate server destinations. It's like having a multilingual city concierge, ensuring smooth communication between neighborhoods and servers.
Run the installer and follow the on-screen instructions.
During the installation process, set a password for the PostgreSQL superuser (default user: postgres).
On macOS:
Use Homebrew to install PostgreSQL:
brew install postgresql
Initialize the database and start the PostgreSQL server:
brew services start postgresql
NB: If you get this error: ERROR: unrecognized configuration parameter "lc_collate", it it probably because there is a version difference between postgreSQL and pgAdmin 4. I had pgAdmin for v16, but postgreSQL v16, so so it wouldn't work. I tried to download postgreSQL v16 but the download page wasn't working, so I decided to develop in v15.
Open pgAdmin and create a new connection using your database credentials.
Programming Languages:
Python (using psycopg2 library):
importpsycopg2defconnect_to_db():
conn=psycopg2.connect(
dbname="mydatabase",
user="myuser",
password="mypassword",
host="localhost",
port="5432"
)
returnconn# Example usageconn=connect_to_db()
print("Connected to the database!")
conn.close()
Additional Tips
Configuration File:
The PostgreSQL configuration files (like postgresql.conf and pg_hba.conf) are typically located in the PostgreSQL data directory. You can adjust settings like listening addresses and authentication methods in these files.
Start/Stop PostgreSQL Service:
On Windows: Use the Services app or pg_ctl command.
On macOS: Use Homebrew services (brew services start postgresql).
On Linux: Use systemctl (sudo systemctl start postgresql).
By following these steps, you should be able to set up and manage a PostgreSQL database on your local machine.
Sample code for connecting from Express backend
To connect to your PostgreSQL database from your Node.js Express backend, you typically use a database client like pg (node-postgres) rather than axios, which is an HTTP client. pg allows you to interact directly with your PostgreSQL database.
Here's a step-by-step guide to setting up a connection to your PostgreSQL database using pg in your Node.js Express backend:
Step 1: Install Necessary Packages
First, you need to install the pg package to connect to your PostgreSQL database and express for your server.
npm install pg express
Step 2: Set Up Your Express Server
Create a new file called server.js (or app.js) for your Express server:
constexpress=require('express');const{ Pool }=require('pg');// Initialize the Express applicationconstapp=express();constport=3000;// Configure the PostgreSQL connectionconstpool=newPool({user: 'myuser',host: 'localhost',database: 'mydatabase',password: 'mypassword',port: 5432,});// Middleware to parse JSON requestsapp.use(express.json());// Example route to test the database connectionapp.get('/test-db',async(req,res)=>{try{constclient=awaitpool.connect();constresult=awaitclient.query('SELECT NOW()');res.json(result.rows);client.release();}catch(err){console.error(err);res.status(500).send('Error connecting to the database');}});// Start the Express serverapp.listen(port,()=>{console.log(`Server is running on port ${port}`);});
Step 3: Create Environment Variables (Optional but Recommended)
For better security and flexibility, use environment variables to store your database credentials. Create a .env file in your project root:
Install the dotenv package to load these environment variables:
npm install dotenv
Then, update your server.js to use these environment variables:
require('dotenv').config();constexpress=require('express');const{ Pool }=require('pg');// Initialize the Express applicationconstapp=express();constport=3000;// Configure the PostgreSQL connection using environment variablesconstpool=newPool({user: process.env.DB_USER,host: process.env.DB_HOST,database: process.env.DB_DATABASE,password: process.env.DB_PASSWORD,port: process.env.DB_PORT,});// Middleware to parse JSON requestsapp.use(express.json());// Example route to test the database connectionapp.get('/test-db',async(req,res)=>{try{constclient=awaitpool.connect();constresult=awaitclient.query('SELECT NOW()');res.json(result.rows);client.release();}catch(err){console.error(err);res.status(500).send('Error connecting to the database');}});// Start the Express serverapp.listen(port,()=>{console.log(`Server is running on port ${port}`);});
Step 4: Start Your Server
Run your server with:
node server.js
Now, you can test the /test-db endpoint by navigating to http://localhost:3000/test-db in your browser or using a tool like Postman. You should see the current date and time returned from your PostgreSQL database.
Summary
Install the pg and express packages.
Set up an Express server.
Configure a PostgreSQL connection using the pg package.
Create an endpoint to test the database connection.
Optionally, use environment variables to store your database credentials securely.
This setup allows your Node.js Express backend to connect to a PostgreSQL database, perform queries, and handle responses.
Import data into a table
In pgAdmin, navigate to and select the table. Rightclick on the table and select import/export. Browse to the file with the data (should be csv). Select the schema of the import file (Normally UTF-8). Click OK.
NB: Dates must be in the format 2024-01-01
When importing data in pgAdmin, the autoincrement in the id field does not work, so you must add the id numbers manually.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Assign a function to a constant using normal anonymous function:
const square = function(x) { return x * x; }
Assign a function to a constant using arrow function:
Think of the constant as a pointer to the function.
const square = (x) => { return x * x; }
A function can also be declared inside an object:
const user = { name: Donn printName() { return this.name; } };
JSX expressions
Assign JSX to constant (note the use of parentheses, not braces)
const userName = "Mike"; const name = ( <p>{UserName}</p> );
//Inside the braces you must put a valid JavaScript expression
It is possible to declare a JSX expression inside a function and assign it to a constant:
const renderMe = () => { const myJSX = ( <p>Something</p> ); ReactDOM.render(myJSX, document.getElementById('root'); }
JSX arrays
Arrays can be displayed directly in JSX: {myArr}
Arrays containing JSX must always contain key values:
[<p key="1">One</p>, <p key="2">Two</p>, <p key="3">Three</p>]
To generate a JSX array from a normal array:
const jsxArray = normalArray.map((elem, key) => { return <p key={key}>{elem}</p>; });
Example from lesson 18:
(Note how the map function omits the use of the return keyword)
Remember that map returns an array, so the map statement must be enclosed within {}
Since it it an expression, no semicolon is required at the end (after the parenthesis
Events and methods
class MyClass extends React.Component {
constructor(props) {
super(props);
}
Context for event handlers must be set explicitly in the class constructor
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myEventHandler = this.myEventHandler.bind(this);
}
With state a component will automatically rerender itself when the data changes
The state object must be created in the constructor.
Changing state does not automatically call render method. Must call this.setState method
this.setState takes a callback function as parameter.
the first parameter of the callback function is prevState by default
Calls to setState are asychronus
The state process:
Setup default state object
Component is rendered with default state (automatic)
Change the state based on an event eg user does something
Re-render the component using new state values (autimatic)
You can have multiple setState expressions in a single event handler:
myEventHandler() {
this.setState((prevState) => {
return {
//Change state
};
});
this.setState((prevState) => {
return {
//Change state again
};
});
}
Changing parent state in its child component
To change state in a child component, pass method using function pointer
If a class component only has a render method, it can be converted to a functional component, where it is not necesary to call the render method:
SFCs do not have access to this keyword
const FuncComponent = (props) => {
return (
(props.prop}
);
};
Alternative syntax:
export default function Button(props){
return {props.label}
}
Default properties for a component:
ClassName.defaultProps = {
name: "default"
}
import {render, screen, fireEvent} from '@testing-library/react'
import Component from './Component'
How to render elements
render(<SomeComponent/>)
Finding elements
To find elements we use the screen. keyword and its methods. Most methods start with 'find', eg findAllByText or 'get' eg getAllByText or 'query', eg queryAllByText. What is the difference between find, get and query?
From Net Ninja tut ep 5. Use find for async operations.
The priority of methods is like this:
From Net Ninja tut ep 6. Prefer the ones at the top. Go down the stack only if the higher methods can't be used.
NB: For this to work you have to set resetMocks: false in react-scripts/scripts/utils/createJestConfig.js.
Before & after each
describe("Some component", () => {
//Add beforeEach hook
beforeEach(() => {
console.log("Running before each test")
})
//AND/OR
//Add beforeAll hook
beforeAll(() => {
console.log("Running once before all tests")
})
// Do the test
it("Shoud test something", () => {...})
//Add afterEach hook
afterEach(() => {
console.log("Running after each test")
})
//AND/OR
//Add afterAll hook
afterAll(() => {
console.log("Running once after all tests")
})
})
Integration tests
A list of typical UI tests
should render element
should be able to type in input
should have empty input when button is clicked
should render the same text passed in to textbox prop
ChatGPT prompt for writing tests
Read the following code and then write a list of tests. You must identify unit tests and integration tests. You do not have to write the code for the tests, just list them for example:
should render element
should be able to type in input... and so on
Workspace Templates: Workspace templates in Visual Studio Code allow you to define and save custom project structures as templates for reuse.
Customization: You can customize your workspace template with specific folder structures, settings, extensions, and even initial files.
Easy Project Setup: Workspace templates streamline project setup by providing a consistent starting point for new projects or workflows.
Sharing: Workspace templates can be shared with team members to ensure consistency across projects and workflows.
Quick Creation: Visual Studio Code makes it easy to create new projects from templates with just a few clicks or commands.
Integration: Workspace templates integrate with other VS Code features like Git, tasks, and debugging, enhancing productivity and collaboration.
Flexibility: Templates can be tailored to various project types, such as web development, Python projects, or TypeScript applications, providing flexibility for different workflows.
Enhanced Development Experience: Using workspace templates promotes a more structured and organized development environment, leading to a better development experience
The key difference between workspace templates and development containers in Visual Studio Code lies in their purpose and functionality:
Workspace Templates:
Purpose: Workspace templates are used to define and save custom project structures, settings, and configurations for reuse in Visual Studio Code.
Functionality: They provide a way to quickly create new projects with a predefined structure and settings.
Customization: Workspace templates can include folder structures, settings, extensions, and initial files tailored to specific project types or workflows.
Usage: They streamline project setup and promote consistency across projects within a team or organization.
Development Containers:
Purpose: Development containers allow developers to create a consistent, isolated, and reproducible development environment using Docker containers.
Functionality: They provide a way to encapsulate dependencies, tools, and configurations within a container, ensuring that all developers work in the same environment regardless of their local setup.
Customization: Development containers can include specific versions of programming languages, frameworks, libraries, and tools required for development.
Usage: They enable developers to develop, debug, and test applications in a containerized environment, enhancing consistency, reproducibility, and collaboration.
While workspace templates and development containers serve different purposes, they can complement each other in certain scenarios:
Combined Use: Workspace templates can be used to define project structures and settings, while development containers provide the underlying development environment within which the project is developed.
Consistency and Reproducibility: Combining workspace templates with development containers ensures consistency and reproducibility not only in project structure but also in the development environment itself.
Scalability: Development containers facilitate scalability by allowing developers to work in identical environments regardless of their local setup, while workspace templates ensure consistency in project structures and settings across teams and projects.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters