Portfolio
One of my recent endeavors involves developing an address validation tool for emergency 911 vehicles. This project showcases my ability to integrate diverse technologies and deliver practical solutions in critical situations.
The core of this tool is a Lightning Web Component, equipped with validation fields and a file upload feature. It operates on a simple yet effective principle: upon address validation, it either triggers a success or error toast event. If an address match is found, the system efficiently returns the Emergency Service Number (ESN). In cases where the address is not directly found, the system cleverly provides a list of similar addresses, allowing the user to select the correct one through a radio button interface.
Accompanying this is a robust backend, written in Python, which handles validation and file uploads. This backend is built using FastAPI and integrates with a database for storing and retrieving E911 data. The combination of Python and Lightning Web Component technologies not only ensures reliability but also offers a user-friendly experience.
Below is a snippet of the JavaScript code for the Lightning Web Component and the Python code for the backend validation and file upload. These excerpts highlight the intricate work involved in creating a reliable and efficient system for a critical public service application.
import { LightningElement} from 'lwc';
import {ShowToastEvent} from 'lightning/platformShowToastEvent';
export default class E911 extends LightningElement {
maybeAddressFound = false;
isLoaded = true;
street=""
city=""
country=""
province=""
postalCode=""
returnedAddress=""
addressList=[]
tempAddress=""
esn=""
provinceOptions = [
{ label: 'ALABAMA', value: 'AL'},
{ label: 'ALASKA', value: 'AK'},
{ label: 'AMERICAN SAMOA', value: 'AS'},
{ label: 'ARIZONA', value: 'AZ'},
{ label: 'ARKANSAS', value: 'AR'},
{ label: 'CALIFORNIA', value: 'CA'},
{ label: 'COLORADO', value: 'CO'},
{ label: 'CONNECTICUT', value: 'CT'},
{ label: 'DELAWARE', value: 'DE'},
{ label: 'DISTRICT OF COLUMBIA', value: 'DC'},
{ label: 'FEDERATED STATES OF MICRONESIA', value: 'FM'},
{ label: 'FLORIDA', value: 'FL'},
{ label: 'GEORGIA', value: 'GA'},
{ label: 'GUAM', value: 'GU'},
{ label: 'HAWAII', value: 'HI'},
{ label: 'IDAHO', value: 'ID'},
{ label: 'ILLINOIS', value: 'IL'},
{ label: 'INDIANA', value: 'IN'},
{ label: 'IOWA', value: 'IA'},
{ label: 'KANSAS', value: 'KS'},
{ label: 'KENTUCKY', value: 'KY'},
{ label: 'LOUISIANA', value: 'LA'},
{ label: 'MAINE', value: 'ME'},
{ label: 'MARSHALL ISLANDS', value: 'MH'},
{ label: 'MARYLAND', value: 'MD'},
{ label: 'MASSACHUSETTS', value: 'MA'},
{ label: 'MICHIGAN', value: 'MI'},
{ label: 'MINNESOTA', value: 'MN'},
{ label: 'MISSISSIPPI', value: 'MS'},
{ label: 'MISSOURI', value: 'MO'},
{ label: 'MONTANA', value: 'MT'},
{ label: 'NEBRASKA', value: 'NE'},
{ label: 'NEVADA', value: 'NV'},
{ label: 'NEW HAMPSHIRE', value: 'NH'},
{ label: 'NEW JERSEY', value: 'NJ'},
{ label: 'NEW MEXICO', value: 'NM'},
{ label: 'NEW YORK', value: 'NY'},
{ label: 'NORTH CAROLINA', value: 'NC'},
{ label: 'NORTH DAKOTA', value: 'ND'},
{ label: 'NORTHERN MARIANA ISLANDS', value: 'MP'},
{ label: 'OHIO', value: 'OH'},
{ label: 'OKLAHOMA', value: 'OK'},
{ label: 'OREGON', value: 'OR'},
{ label: 'PALAU', value: 'PW'},
{ label: 'PENNSYLVANIA', value: 'PA'},
{ label: 'PUERTO RICO', value: 'PR'},
{ label: 'RHODE ISLAND', value: 'RI'},
{ label: 'SOUTH CAROLINA', value: 'SC'},
{ label: 'SOUTH DAKOTA', value: 'SD'},
{ label: 'TENNESSEE', value: 'TN'},
{ label: 'TEXAS', value: 'TX'},
{ label: 'UTAH', value: 'UT'},
{ label: 'VERMONT', value: 'VT'},
{ label: 'VIRGIN ISLANDS', value: 'VI'},
{ label: 'VIRGINIA', value: 'VA'},
{ label: 'WASHINGTON', value: 'WA'},
{ label: 'WEST VIRGINIA', value: 'WV'},
{ label: 'WISCONSIN', value: 'WI'},
{ label: 'WYOMING', value: 'WY' }
]
handleChange(event){
this.street = event.target.street
this.city = event.target.city
this.province = event.target.province
this.postalCode = event.target.postalCode
this.country = event.target.country
}
async validate(){
this.esn = ""
this.maybeAddressFound = false;
const calloutURI = '/validate';
await fetch(calloutURI + '?' + new URLSearchParams({
street: this.street,
city: this.city,
state: this.province,
postalcode: this.postalCode,
country: this.country}),
{
method: "GET",
}).then((response) => {
return response.json()
}).then((json) => {
if (json.validate === 'exists'){
console.log(json)
console.log(json.query_object[0].esn)
this.esn = json.query_object[0].esn
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'This address exists',
variant: 'success',
}),
);
} else if (json.validate === 'maybe') {
this.addressList = json.addressList
this.addressList = this.addressList.map((address) => {
return {label: address, value: address}
})
this.maybeAddressFound = true
} else {
this.dispatchEvent(
new ShowToastEvent({
title: 'Failed',
message: 'This address does NOT exist',
variant: 'failed',
}),
);
}
})
}
dontReplaceAddress() {
this.maybeAddressFound = false
this.dispatchEvent(
new ShowToastEvent({
title: 'Failed',
message: 'This address does NOT exist',
variant: 'failed',
}),
);
}
replaceAddress() {
const addr = this.tempAddress.split(",")
console.log(this.tempAddress.split(","))
this.street = addr[0]
this.city = addr[1]
this.maybeAddressFound = false
}
addressChange(event) {
this.tempAddress = event.detail.value;
}
get getProvinceOptions() {
return this.provinceOptions;
}
upload(uploadedFiles){
const calloutURI = '/file_upload';
const form = new FormData
form.append("file", uploadedFiles)
fetch(calloutURI, {
method: "POST",
body: form,
}).then((response) => {
if (response.ok){
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'File uploaded Successfully',
variant: 'success',
}),
);
} else {
this.dispatchEvent(
new ShowToastEvent({
title: 'Failed',
message: 'File failed to upload',
variant: 'failed',
}),
);
}
this.isLoaded = true;
})
}
handleUploadFinished(event) {
this.isLoaded = false
this.upload(event.target.files[0])
}
}
from fastapi import FastAPI, UploadFile, File, Response, Depends
from fastapi.middleware.cors import CORSMiddleware
from openpyxl import load_workbook
import json
from models import Session
from models.e911Model import E911data, create_table, drop_table
app = FastAPI()
origins = [
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)
def get_db():
session = Session()
try:
yield session
finally:
session.close()
@app.get("/ping")
async def healthcheck():
return {'Test': 'OK'}
def load_file_data(request):
with open('temp.xlsx', 'wb') as f:
b = request.read()
f.write(b)
book = load_workbook('temp.xlsx')
sheet = book.active
rows = list(sheet.rows)
headers = [x.value for x in rows[0]]
return [dict(zip(headers, [x.value for x in row])) for row in rows[1:]]
def validator(x):
if isinstance(x, int):
return x >= 0
elif isinstance(x, str):
return x != ''
else:
print(x)
return x
def strip_periods_and_spaces(string: str):
string = string.strip()
if string.endswith('.'):
return string.replace('.', '')
else:
return string
def import_data(session, filename=None):
formatted_data = load_file_data(filename)
drop_table()
create_table()
for d in formatted_data:
if d['DIR']:
dir = strip_periods_and_spaces(d['DIR'])
else:
dir=''
street = strip_periods_and_spaces(d['STREET'])
length = len(street)
# Getting rid of the abbreviation and spelling out the whole direction ie N = NORTH
if street[-1] == 'N' and street[length-2] == ' ':
street = street.replace('N', 'NORTH')
if street[-1] == 'S' and street[length-2] == ' ':
street = street.replace('S', 'SOUTH')
if street[-1] == 'E' and street[length-2] == ' ':
street = street.replace('E', 'EAST')
if street[-1] == 'W' and street[length-2] == ' ':
street = street.replace('W', 'WEST')
houselow = d['HOUSELOW']
househigh = d['HOUSEHIGH']
city = strip_periods_and_spaces(d['CITY'])
state = strip_periods_and_spaces(d['STATE'])
esn = d['ESN']
validated = list(map(validator, [street, houselow, househigh, city, state, esn]))
if not all(validated):
print(d, [street, houselow, househigh, city, state, esn])
break
entry = E911data(
dir=dir,
street=street,
houselow=houselow,
househigh=househigh,
city=city,
state=state,
esn=esn,
)
session.add(entry)
session.commit()
@app.post("/file_upload")
async def file_upload(file: UploadFile = File(...), session: Session = Depends(get_db)):
if not file:
return {"message": "No upload file sent"}
else:
import_data(session, file.file)
return {"message": "file sent"}
def query_address(session, city, final_dir, house_number, street_name):
query_object = session.query(E911data.dir, E911data.city, E911data.state, E911data.street, E911data.esn).filter(
E911data.city == city,
E911data.dir == final_dir,
E911data.houselow <= int(house_number),
E911data.househigh >= int(house_number),
E911data.street == street_name).all()
return query_object
@app.get("/validate")
async def validate_address(street: str = '', city: str = '', state: str = 'UT', country: str = 'US',
postalcode: str = 00000, session: Session = Depends(get_db)):
final_dir = ''
house_number = ''
street_name = ''
street = street.upper().strip()
street_list = street.split(' ')
need_direction = True
if street == '' or city == '':
return {'validate': False}
# strip out any .
for index, item in enumerate(street_list):
street_list[index] = item.strip('.')
direction = street_list[0]
# If there is no direction
if direction[-1].isnumeric() and (street_list[1] != 'N'
and street_list[1] != 'S'
and street_list[1] != 'E'
and street_list[1] != 'W'
and street_list[1] != 'NORTH'
and street_list[1] != 'SOUTH'
and street_list[1] != 'EAST'
and street_list[1] != 'WEST'):
house_number = street_list[0]
final_dir = ''
for ins in street_list[1:]:
street_name = street_name + ' ' + ins
# strip spaces off of beginning and end of street_name
street_name = street_name.strip()
need_direction = False
# if direction is typed out it needs to be an abbreviation
if direction.endswith('NORTH'):
direction = direction.replace('NORTH', 'N')
elif direction.endswith('SOUTH'):
direction = direction.replace('SOUTH', 'S')
elif direction.endswith('EAST'):
direction = direction.replace('EAST', 'E')
elif direction.endswith('WEST'):
direction = direction.replace('WEST', 'W')
size = len(direction)
# separating the direction and house number
if direction.endswith('N') or direction.endswith('S') or direction.endswith('E') or direction.endswith('W'):
final_dir = direction[-1]
house_number = direction[0:size-1]
for ins in street_list[1:]:
street_name = street_name + ' ' + ins
# strip spaces off of beginning and end of street_name
street_name = street_name.strip()
else:
# if there is no direction this can be skipped
if need_direction:
final_dir = street_list[1]
house_number = street_list[0]
for ins in street_list[2:]:
street_name = street_name + ' ' + ins
# strip spaces off of beginning and end of street_name
street_name = street_name.strip()
city = city.upper().strip()
# Setting the direction to be an abbreviation
if final_dir == 'NORTH':
final_dir = 'N'
if final_dir == 'SOUTH':
final_dir = 'S'
if final_dir == 'EAST':
final_dir = 'E'
if final_dir == 'WEST':
final_dir = 'W'
# if there is no space after the street number and the direction, this adds the space
length = len(street_name)
if street_name.endswith('NORTH') and street_name[length - 6] != ' ':
street_name = street_name.replace('NORTH', ' NORTH')
if street_name.endswith('SOUTH') and street_name[length - 6] != ' ':
street_name = street_name.replace('SOUTH', ' SOUTH')
if street_name.endswith('EAST') and street_name[length - 5] != ' ':
street_name = street_name.replace('EAST', ' EAST')
if street_name.endswith('WEST') and street_name[length - 5] != ' ':
street_name = street_name.replace('WEST', ' WEST')
# if there is only an abbreviation, it will replace it with the full direction name
length = len(street_name)
if street_name.endswith('N') and street_name[length - 2] == ' ':
street_name = street_name.replace('N', 'NORTH')
if street_name.endswith('S') and street_name[length - 2] == ' ':
street_name = street_name.replace('S', 'SOUTH')
if street_name.endswith('E') and street_name[length - 2] == ' ':
street_name = street_name.replace('E', 'EAST')
if street_name.endswith('W') and street_name[length - 2] == ' ':
street_name = street_name.replace('W', 'WEST')
# if there is only an abbreviation and no space it will put in a space and the full direction
length = len(street_name)
if street_name.endswith('N') and street_name[length - 2].isnumeric():
street_name = street_name.replace('N', ' NORTH')
if street_name.endswith('S') and street_name[length - 2].isnumeric():
street_name = street_name.replace('S', ' SOUTH')
if street_name.endswith('E') and street_name[length - 2].isnumeric():
street_name = street_name.replace('E', ' EAST')
if street_name.endswith('W') and street_name[length - 2].isnumeric():
street_name = street_name.replace('W', ' WEST')
if not house_number.isnumeric():
return {'validate': False}
# If we have an exact hit, return that the address was found
query_object = query_address(session, city, final_dir, house_number, street_name)
if len(query_object) > 0:
return {'validate': 'exists',
'query_object': query_object}
else:
# Iterate though all strings in the street name and get a query of each string, put them in a list
final_address_list = set()
c = city.split()
for street in street_name.split():
query_object = session.query(E911data.dir, E911data.city, E911data.state, E911data.street, E911data.esn).filter(
E911data.street.ilike(f'%{street}%'),
E911data.city.ilike(f'{c[0]}%'),
# E911data.city.match(f'{c[0]}%'),
E911data.houselow <= int(house_number), E911data.househigh >= int(house_number)).all()
if query_object:
for obj in query_object:
address = obj
if len(address) == 5:
final_dir = address[0]
city = address[1]
street_name = address[3]
esn = address[-1]
if house_number + ' ' + final_dir + ' ' + street_name not in final_address_list:
final_address_list.add(house_number + ' ' + final_dir + ' ' + street_name + ', ' + city)
if len(address) == 4:
city = address[0]
street_name = address[2]
esn = address[-1]
if house_number + ' ' + final_dir + ' ' + street_name not in final_address_list:
final_address_list.add(house_number + ' ' + final_dir + ' ' + street_name + ', ' + city)
if len(final_address_list) > 0:
f_address_list = sorted(final_address_list)
return {'validate': 'maybe',
'addressList': f_address_list
}
else:
return {'validate': False}