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

Completion of Challenges at Headstorm #104

Open
wants to merge 1 commit into
base: master
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
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 Headstorm
Copyright (c) 2022 Francisco Munoz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
## Headstorm Interview
# HeadStorm_Challenge
Repository that holds work for the HeadStorm Challenge

Welcome to the Headstorm interview challenge! This repository is designed for candidates to [fork and create Pull Requests](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork) with their solutions. There are two types of 'take-home' problems here:
## backEnd_challenge.py
This is the file that holds the code for the back end challenge. It is a standalone file with on dependencies on any other file.

### Challenges
These are domain specific problems that can be submitted individually. You can choose from backend, frontend, databases, or data-science. You can submit a PR for one, many, or all the challenges.
## database_challenge.py
This is the file that holds the code for the database challenge. Using postgreSQL, python commands were used to create the database, the tables, and the INSERT commands to insert the data into the tables. Some dependencies include the testingFile.py, which randomly generated 25 entries that would be used to insert into the tables in the database and the oldData.txt, which held this information. The database_relationalModel.jpg shows the ER model of how this database is constructed.

### Interviews
These are language specific interview questions and you can choose the language in which you implement your solution.
## frontEnd_Challenge.html
This is the file that holds the code for the front end challenge. One of the dependencies is the browserIcon.png file that is used for the icon on the browser, but aside from that this html file is a standalone file.
79 changes: 79 additions & 0 deletions backEnd_challenge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
Assumptions made:
1. For the GET method, assuming that whenever that GET method is ran, list will always be size 500,
so no need to check and just return the sorted list.

2. For the overall API, assuming this would be ran locally so enabled it to be ran locally. Otherwise,
possible to corrected and be ran on a server and use a curl command to access it.
"""

"""
Used Flask to be able to create the REST API and used some in built functions to be able to execute
certain calculations more efficiently.
"""

from flask import Flask, request
from flask_restful import Resource, Api, reqparse, abort
import pandas as pd
import ast
import random, json, requests, re, bisect

app = Flask(__name__)
api = Api(app)
NUMBERLIST = {"list":[]}

# Class Declaration that contains all 3 different methods
class ListData(Resource):
# Retrieve Data, sort before returning
def get(self):
NUMBERLIST['list'].sort()
return NUMBERLIST

# Create Data, make sure all entries are numbers and size is of 500
def post(self):
numlist = []
templist = str(request.data).split(',')
for i in templist:
temp = re.sub("[^0-9]", "", i)
numlist.append(int(temp))

if(len(numlist) == 500):
result = all(isinstance(x, int) for x in numlist)
if (result == True):
NUMBERLIST['list'] = numlist
return NUMBERLIST
else:
abort(400,"Invalid Input. All entries have to be numbers.")
else:
abort(400, "Invalid input. Length is not 500.")

# Insert one element in corresponding order
def patch(self):
entry = str(request.data).strip()
temp = re.sub("[^0-9]", "", entry)

# Check if the single entry is a number or not
if(temp.isnumeric()):
# Use built in function to insert entry in a sorted list
bisect.insort(NUMBERLIST['list'], int(temp))
return NUMBERLIST
else:
abort(400,"Invalid Input. All entries have to be numbers.")

api.add_resource(ListData, '/data/') # '/data' is our entry point
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)


# Testing Commands
payload = []
for i in range(0, 500):
payload.append(random.randint(0,1000))

newPayload = json.dumps(payload)
newData = str(random.randint(0,1000))

r=requests.post("http://localhost:5000/data/",data=newPayload)
r=requests.get("http://localhost:5000/data/")
r=requests.patch("http://localhost:5000/data/",data=newData)

Binary file added browserIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions database_challenge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import psycopg2

# Variables that will be used for this program
customerTable = '''CREATE TABLE IF NOT EXISTS Customer
(customerID INT PRIMARY KEY NOT NULL,
Name VARCHAR(50) NOT NULL,
Address VARCHAR(256) NOT NULL,
CellPhone VARCHAR(30) NOT NULL,
Email VARCHAR(30) NOT NULL,
WorkPhone VARCHAR(50) NOT NULL)
;'''

recordsTable = '''CREATE TABLE IF NOT EXISTS Records
(recordID INT PRIMARY KEY NOT NULL,
AdvWidgetOrder INT NOT NULL,
BasicWidgetOrder INT NOT NULL,
ProtectPlan BOOLEAN NOT NULL,
customerID INT NOT NULL,
FOREIGN KEY(customerID) REFERENCES Customer(customerID))
;'''

#establishing the connection
conn = psycopg2.connect(
database="postgres", user='postgres', password='password', host='127.0.0.1', port= '5432'
)
#Creating a cursor object using the cursor() method
cursor = conn.cursor()

# Create Tables if the tables don't exist
cursor.execute(customerTable)
cursor.execute(recordsTable)

#Closing the connection
conn.close()

# Since Database is created and the tables have been created successfully, we need to migrate the old data
# into this new database model. Here we will read in the JSON file (assuming it is structured in a normal text
# file). We will also assume that the data will come in as defined in the table on Github under the Database Challenge
# Description.
# Assumption here is that the data will be separated by semicolons to make the splitting easier but depending how they are split,
# we can make changes to the splitting logic and it would still work.

dataFile = open('oldData.txt', 'r')
i = 1
j = 2
for line in dataFile:
tempLine = line.split(';')
customerString = '''INSERT INTO Customer(customerID, Name, Address, CellPhone, Email, WorkPhone)
VALUES ({}, {}, {}, {}, {}, {})'''.format(i, tempLine[1], tempLine[5], tempLine[2], tempLine[4], tempLine[3])

recordString = '''INSERT INTO Records(recordID, AdvWidgetOrder, BasicWidgetOrder, ProtectPlan,
customerID) VALUES ({}, {}, {}, {}, {})'''.format(j, int(tempLine[7]), int(tempLine[6]), bool(tempLine[8]), i)
j = j + 1
i = i + 1

dataFile.close()
Binary file added database_relationalModel.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions frontEnd_Challenge.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!--
[INCOMPLETE]
Google reCaptcha V3 implement in page. Submission of form requires Google captcha pass

The implementation code for incorporating Google reCaptcha v3 was not difficult. The difficult part
that I was having trouble was using the keys and adding the local host as one of the sites. Apart from that,
the website will present a basic contact form where the user is expected to input their information.
That information will then be printed out on the Browser Console.
-->

<!--
Assumptions that were made here is that the only information would be needed is the contact us form
And that data would then be dumped into the console log. Other than that, made some changes to center it
and to include the icon in the browser with a local file that is included with this file.
-->


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Include Title of the Company, not really sure what else to put so extended the title a little bit-->
<title>Company Title: A New Horizon</title>
<!-- Icon in the browser tab -->
<link rel="icon" href="browserIcon.png">
</head>

<!-- Scripts that will be needed for this website applicaiton to work -->
<script>
function onSubmit(token)
{
console.log("Results");
document.getElementById("contact-form").submit();
console.log("First Name:" + document.getElementById("fname").value);
console.log("Last Name:" + document.getElementById("lname").value);
console.log("Phone Number:" + document.getElementById("number").value);
console.log("Email:" + document.getElementById("email").value);
}
</script>

<!-- Information of the body that will be displayed on the website -->
<body style="text-align: center;">
<div class="wrapper">
<h1>Contact Me</h1>
<form id="contact-form" onsubmit="onSubmit()">

<label for="fname">First Name</label><br>
<input type="text" id="fname" name="fname" value=""><br>
<label for="lname">Last Name</label><br>
<input type="text" id="lname" name="lname" value=""><br>
<label for="number">Phone Number</label><br>
<input type="text" id="number" name="number" value=""><br>
<label for="pnum">Email </label><br>
<input type="text" id="email" name="email" value=""><br>
</form>
<button type="submit" form="contact-form" value="submit">Submit</button>
</div>
</body>
</html>
25 changes: 25 additions & 0 deletions oldData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
1785; Mary Simmer; 2690175222; 1304370303; [email protected]; 6356 Bethany Ranch Apt. 796 Brownfurt, IA 98767; 604; 1528; True;
1045; Martha Mccoy; 8179795075; 6978684276; [email protected]; 04307 Monica Mall West Breanna, ME 51243; 609; 624; False;
1967; Charlotte Hershey; 1214902815; 6735265431; [email protected]; 756 Jacqueline Crescent Apt. 072 Victoriachester, HI 55142; 1623; 1605; True;
925; Idella Brown; 8949144699; 6563726364; [email protected]; 4173 Kathleen Court Apt. 962 Julieburgh, AR 67414; 1037; 1741; False;
254; Martin Thompson; 7754106150; 9673530514; [email protected]; 11457 Russell Parkways Apt. 449 Port Curtischester, NJ 45460; 1613; 314; False;
1024; Bonnie Mitchell; 1846020140; 9296540382; [email protected]; Unit 9708 Box 4539 DPO AE 18616; 1613; 1771; False;
1984; Marie Orona; 3539449144; 2356949131; [email protected]; 545 Rodgers Bypass Millerberg, NC 28758; 912; 1383; False;
565; Julie Pierce; 9099331270; 7645174016; [email protected]; PSC 9081, Box 2446 APO AE 81270; 946; 646; False;
1123; Sonja Wagoner; 1006289674; 7608903378; [email protected]; 508 Leslie Summit Suite 638 East Gabriel, ND 48735; 1063; 461; True;
909; David Cross; 3142926865; 7611185394; [email protected]; 76847 Wright Turnpike Apt. 457 Millerland, IL 65899; 650; 105; False;
940; Susan Newton; 2445331621; 4159013134; [email protected]; 54783 Austin Shoals Suite 668 Allenberg, VT 46440; 308; 48; False;
6; Ruth Saldivar; 2288169164; 4530547090; [email protected]; 28833 Felicia Radial Lake Micheleshire, HI 87840; 195; 1404; False;
844; Cassandra Jones; 9031806207; 7663108826; [email protected]; 461 Raymond Meadows North Adamborough, OK 17005; 48; 937; False;
1986; Jayme Murphy; 3371272946; 1779622004; [email protected]; 993 Holden Camp Apt. 437 West Lisaborough, WV 69178; 1452; 1556; False;
1035; Mary Fyall; 8428725296; 1087071071; [email protected]; 20910 Dylan Heights Apt. 178 Rodriguezborough, DE 56334; 1967; 325; False;
1682; Clint Barnes; 1958875411; 9555349579; [email protected]; 3602 Joe Underpass Suite 295 East Mariabury, LA 86858; 181; 722; True;
154; Yesenia Crook; 6278970113; 7991538452; [email protected]; 111 Stevens Pike Suite 147 West Juanside, AK 12854; 1754; 1682; True;
1244; Barbara Wallace; 1454107749; 8763131082; [email protected]; 92263 Kimberly Pass South Mary, TX 19471; 1532; 1740; True;
988; Ina Koelling; 6579626087; 9289509798; [email protected]; 06446 Robert Glen Apt. 833 Andrewview, WI 14681; 1837; 1400; False;
1785; David Cooper; 4670865569; 8284376404; [email protected]; PSC 3558, Box 4253 APO AA 64934; 1410; 1669; True;
706; Brian Koroma; 1890871912; 4899792378; [email protected]; 638 Jacob Manor Apt. 189 Leeberg, MD 00888; 1869; 1852; False;
1515; Megan Miller; 7089943029; 5513552086; [email protected]; 829 Cook Bypass Morganfurt, FL 65614; 685; 1495; True;
698; Doris Liefer; 3336404101; 5898317116; [email protected]; 951 Chung Skyway East Kimberlyview, VT 12746; 1487; 592; True;
948; Gayle Vidot; 8777934481; 1175692524; [email protected]; 713 Glenn Park North Williamville, MI 57301; 1271; 1659; False;
1291; Brenda Maddox; 3983690736; 6983501758; [email protected]; 93209 Spears Throughway South Heather, CT 42645; 1654; 1555; False;
34 changes: 34 additions & 0 deletions testingFile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import random, names, string
from faker import Faker
import json
from random import randint

oldData = []
fake = Faker()

def random_char(y):
return ''.join(random.choice(string.ascii_letters) for x in range(y))

def random_with_N_digits(n):
range_start = 10**(n-1)
range_end = (10**n)-1
return randint(range_start, range_end)


textfile = open("oldData.txt", "w")
for i in range(0,25):
record = random.randint(0,2000)
basicWidgetOrder = random.randint(0,2000)
advWidgetOrder = random.randint(0,2000)
protectPlan = bool(random.getrandbits(1))
fullName = names.get_full_name()
cellPhone = str(random_with_N_digits(10))
workPhone = str(random_with_N_digits(10))
email = (random_char(15) + "@gmail.com")
address = fake.address().replace('\n', ' ')
tempData = [record, fullName, cellPhone, workPhone, email, address, basicWidgetOrder, advWidgetOrder, protectPlan]
for j in tempData:
textfile.write(str(j) + '; ')
textfile.write('\n')

textfile.close()