-
Notifications
You must be signed in to change notification settings - Fork 112
Jeremy Kracy #89
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
base: master
Are you sure you want to change the base?
Jeremy Kracy #89
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[{"Record ID":2279,"Name":"Kalila Badrock","Cell Phone":"813-953-0689","Work Phone":"469-669-0547","Email":"[email protected]","Address":"0 Stoughton Place","Basic Widget Order":30,"Advanced Widget Order":58,"Protection Plan":true}, | ||
{"Record ID":7488,"Name":"Merrily Burds","Cell Phone":"711-916-0235","Work Phone":"469-980-1811","Email":"[email protected]","Address":"752 Hanover Pass","Basic Widget Order":34,"Advanced Widget Order":94,"Protection Plan":false}, | ||
{"Record ID":2926,"Name":"Adrian Orae","Cell Phone":"497-393-4258","Work Phone":"609-701-0442","Email":"[email protected]","Address":"692 Randy Park","Basic Widget Order":89,"Advanced Widget Order":10,"Protection Plan":false}, | ||
{"Record ID":7788,"Name":"Penni Lethabridge","Cell Phone":"938-905-6654","Work Phone":"453-269-0061","Email":"[email protected]","Address":"5 New Castle Court","Basic Widget Order":87,"Advanced Widget Order":100,"Protection Plan":false}, | ||
{"Record ID":9357,"Name":"Missy Dinning","Cell Phone":"804-660-7935","Work Phone":"203-577-4126","Email":"[email protected]","Address":"007 Larry Court","Basic Widget Order":21,"Advanced Widget Order":73,"Protection Plan":false}, | ||
{"Record ID":9333,"Name":"Ronica Thorne","Cell Phone":"529-483-3697","Work Phone":"236-451-5815","Email":"[email protected]","Address":"26 High Crossing Place","Basic Widget Order":56,"Advanced Widget Order":95,"Protection Plan":true}, | ||
{"Record ID":3172,"Name":"Margit Marquis","Cell Phone":"539-728-5606","Work Phone":"885-138-8678","Email":"[email protected]","Address":"149 Barby Crossing","Basic Widget Order":74,"Advanced Widget Order":52,"Protection Plan":true}, | ||
{"Record ID":3326,"Name":"Travis Lathe","Cell Phone":"228-622-7391","Work Phone":"319-631-4135","Email":"[email protected]","Address":"2 Gateway Park","Basic Widget Order":92,"Advanced Widget Order":100,"Protection Plan":true}, | ||
{"Record ID":2206,"Name":"Chalmers Vedyashkin","Cell Phone":"334-958-5613","Work Phone":"268-547-1288","Email":"[email protected]","Address":"1 Dexter Hill","Basic Widget Order":16,"Advanced Widget Order":25,"Protection Plan":false}, | ||
{"Record ID":8769,"Name":"Ripley Chant","Cell Phone":"549-606-8500","Work Phone":"583-341-3201","Email":"[email protected]","Address":"5 Lighthouse Bay Crossing","Basic Widget Order":24,"Advanced Widget Order":87,"Protection Plan":true}] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import json | ||
|
||
|
||
def read_in(file_name): | ||
file = open(file_name, 'r') | ||
data = json.load(file) | ||
|
||
print('CREATE TABLE Customer_Information (\n' | ||
'Email varchar(50) NOT NULL,\n' | ||
'Name varchar(50),\n' | ||
'Cell_Phone varchar(10),\n' | ||
'Work_Phone varchar(10),\n' | ||
'Address varchar(50),\n' | ||
'PRIMARY KEY (Email)\n' | ||
').\n') | ||
print('CREATE TABLE Order_Information (\n' | ||
'Record_ID int NOT NULL,\n' | ||
'Basic_Widget_Order int,\n' | ||
'Advanced_Widget_Order int,\n' | ||
'Protection Plan BOOLEAN,\n' | ||
'Email varchar(50) NOT NULL,\n' | ||
'PRIMARY KEY (Record_ID),\n' | ||
'FOREIGN KEY (Email) REFERENCES Customer_Information(Email)\n' | ||
').\n') | ||
|
||
for i in data: | ||
print('INSERT INTO CUSTOMER_INFORMATION (Email, Name, Cell_Phone, Work_Phone, Address)\n' | ||
'VALUES ({}, {}, {}, {}, {})\n'.format(i['Email'], i['Name'], i['Cell Phone'], i['Work Phone'], i['Address'])) | ||
|
||
print('INSERT INTO Order_Information (Record_ID, Basic_Widget_Order, Advanced_Widget_Order, Protection_Plan, Email)\n' | ||
'VALUES ({}, {}, {}, {}, {})\n'.format(i['Record ID'], i['Basic Widget Order'], i['Advanced Widget Order'], i['Protection Plan'], i['Email'])) | ||
|
||
if __name__ == '__main__': | ||
|
||
read_in('data.json') | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> | ||
|
||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | ||
<link rel="icon" type="image/png" href="profile pic.png"> | ||
<link rel="stylesheet" href="mystyle.css"> | ||
<script src="https://www.google.com/recaptcha/api.js" async defer></script> | ||
<body> | ||
|
||
<div style="background:#097524" class="jumbotron"> | ||
<h1 class="text-white">Jeremy Kracy, LLC</h1> | ||
<p class="text-white">Author: Jeremy Kracy</p> | ||
</div> | ||
|
||
<div id="after_submit"></div> | ||
<form id="contact_form" action="" onsubmit="sConsole(event)" enctype="multipart/form-data"> | ||
<div class="row"> | ||
<div class="col px-sm-4"> | ||
<label class="required" for="name">Your name:</label><br /> | ||
<input id="name" class="input" name="name" type="text" value="" size="30" /><br /> | ||
<span id="name_validation" class="error_message"></span> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col px-sm-4"> | ||
<label class="required" for="email">Your email:</label><br /> | ||
<input id="email" class="input" name="email" type="text" value="" size="30" /><br /> | ||
<span id="email_validation" class="error_message"></span> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col px-sm-4"> | ||
<label class="required" for="message">Your message:</label><br /> | ||
<textarea id="message" class="input" name="message" rows="7" cols="30"></textarea><br /> | ||
<span id="message_validation" class="error_message"></span> | ||
</div> | ||
</div> | ||
<div class="col px-sm-2"> | ||
<div class="g-recaptcha" data-sitekey="6LdwoaEaAAAAANI_ZCSKM_sMK_wYc_OfUW1B-xtL"></div> | ||
</div> | ||
<br/> | ||
<div class="col px-sm-2"> | ||
<input id="submit_button" type="submit" value="Submit form" /> | ||
</div> | ||
</form> | ||
|
||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> | ||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> | ||
</body> | ||
</head> | ||
</html> | ||
|
||
<script type: "text/javascript"> | ||
function sConsole(event) { | ||
event.preventDefault(); | ||
var name = document.getElementById("name"); | ||
var email = document.getElementById("email"); | ||
var message = document.getElementById("message"); | ||
console.log(name.value); | ||
console.log(email.value); | ||
console.log(message.value); | ||
} | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
label { | ||
font-weight: bold; | ||
font-size: 16px; | ||
} | ||
|
||
#submit_button { | ||
background-color: #097524; | ||
height: 30px; | ||
width: 20%; | ||
color: #FFFFFF; | ||
font-weight: bold; | ||
} | ||
|
||
input, textarea { | ||
background-color: #D3D3D3; | ||
color: #2F4F4F; | ||
width: 250px; | ||
margin-bottom: 10px; | ||
box-shadow: 5px 5px 2px 2px #696969; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Jeremy Kracy | ||
|
||
## Frontend Challenge | ||
I am not very experienced with webpage design. I do have a bit of experience working with html and css, but nothing extensive. I decided to use the bootstrap framework to design the layout on the webpage. I implemented the reCaptcha using the link referenced on the challenge instructions. | ||
|
||
## Backend Challenge | ||
I am not very experienced when it comes to working with APIs or designing them. I decided to use node.js with a mongoDB atlas cloud database to store my data. I used the mongoose extension to interact with my database. | ||
|
||
## Database Challenge | ||
I was most confident going into this challenge, because it is something I have done before. I am confident in my ability to make good decisions in regards to database design. I chose to use python for this assignment, because of how simple it is to work with .json files in python. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const mongoose = require('mongoose'); | ||
|
||
const dataSchema = mongoose.Schema({ | ||
_id: mongoose.Schema.Types.ObjectId, | ||
data: [{type: Number, required: true }] | ||
}); | ||
|
||
module.exports = mongoose.model('Data', dataSchema); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
const express = require('express'); | ||
const router = express.Router(); | ||
const mongoose = require('mongoose'); | ||
|
||
const Data = require('../models/number'); | ||
|
||
router.get('/', (req, res, next) => { | ||
Data.find() | ||
.select('data _id') | ||
.exec() | ||
.then(docs => { | ||
res.status(200).json(docs); | ||
}) | ||
.catch(err => { | ||
console.log(err); | ||
res.status(500).json({ | ||
error: err | ||
}) | ||
}); | ||
}); | ||
|
||
router.get('/:dataId', (req, res, next) => { | ||
const id = req.params.dataId; | ||
Data.findById(id) | ||
.select('data _id') | ||
.exec() | ||
.then(doc => { | ||
if(doc) { | ||
res.status(200).json(doc); | ||
} else { | ||
res.status(404).json({ | ||
message: "No valid entry for provided ID" | ||
}); | ||
} | ||
}) | ||
.catch(err => { | ||
console.log(err); | ||
res.status(500).json({ | ||
error: err | ||
}) | ||
}); | ||
}); | ||
|
||
|
||
router.post('/', (req, res, next) => { | ||
const data = new Data({ | ||
_id: new mongoose.Types.ObjectId(), | ||
data: req.body.data | ||
}); | ||
console.log(data.data.length); | ||
if(data.data.length === 500){ | ||
data.save() | ||
.then(result => { | ||
console.log(result); | ||
console.log(result.data.length); | ||
|
||
res.status(201).json({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How did you decide on 201 here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used the 201 status code to verify that a new object was created in the database using that POST request. This is in line with my understanding of the "201 Created" code. |
||
message: 'Data created', | ||
created: result, | ||
request: { | ||
type: 'GET', | ||
url: 'http://localhost:3000/data/' + result._id | ||
} | ||
}); | ||
}) | ||
.catch(err => { | ||
console.log(err); | ||
res.status(500).json({ | ||
error: err | ||
}); | ||
}); | ||
} else { | ||
res.status(500).json({ | ||
error: 'Object list is not 500 objects in length' | ||
}); | ||
} | ||
|
||
}); | ||
|
||
router.patch('/:dataId', (req, res, next) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you tell me how did you decide to use patch here? As in what purpose does it serve given the context of the problem you're solving. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My intention with the use of patch was to allow a user to update any given array in the database with new information without having to create an entirely new object in the database. I imagine a user would use a get request to attain the available array IDs, and use this information in a patch call to update the desired array. |
||
const id = req.params.dataId; | ||
if(req.body.data.length === 500) { | ||
Data.updateOne({_id: id }, {$set: {data: req.body.data}}) | ||
.exec() | ||
.then(doc => { | ||
console.log(doc); | ||
res.status(200).json({ | ||
data: doc, | ||
request: { | ||
type: 'GET', | ||
url: 'http://localhost:3000/data/' + id | ||
} | ||
}); | ||
}) | ||
.catch(err => { | ||
console.log(err); | ||
res.status(500).json({ | ||
error: err | ||
}); | ||
}); | ||
} else { | ||
res.status(500).json({ | ||
error: 'Object list is not 500 objects in length OR data is invalid' | ||
}); | ||
} | ||
}); | ||
|
||
module.exports = router; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
const express = require('express'); | ||
const app = express(); | ||
const morgan = require('morgan'); | ||
const bodyParser = require('body-parser'); | ||
const mongoose = require('mongoose'); | ||
|
||
|
||
const dataRoutes = require('./api/routes/data'); | ||
|
||
mongoose.connect('mongodb+srv://HeadstormChallenge:[email protected]/myFirstDatabase?retryWrites=true&w=majority'); | ||
|
||
app.use(morgan('dev')); | ||
app.use(bodyParser.urlencoded({extended: false})); | ||
app.use(bodyParser.json()); | ||
|
||
app.use((req, res, next) => { | ||
res.header('Access-Control-Allow-Origin', '*'); | ||
res.header('Access-Control-Allow-Headers', '*'); | ||
if(req.method === 'OPTIONS') { | ||
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH'); | ||
return res.status(200).json({}); | ||
} | ||
next(); | ||
}); | ||
|
||
// Routes to handle requests | ||
app.use('/data', dataRoutes); | ||
|
||
app.use((req, res, next) => { | ||
const error = new Error('Not Found'); | ||
error.status = 404; | ||
next(error); | ||
}); | ||
|
||
app.use((error, req, res, next) => { | ||
res.status(error.status || 500); | ||
res.json({ | ||
error: { | ||
message: error.message | ||
} | ||
}); | ||
}); | ||
|
||
module.exports = app; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"env": { | ||
"MONGO_ATLAS_PW": "headstorm" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What was your thought process in deciding what primary key to use for Customer_Information table? And what kind of relationship do you anticipate between the two tables (Customer_Information and Order_Information)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to use the customer's email as the primary key in the Customer_Information table, because it seemed to be the best characteristic to use as an identifier. I think of other account based services that will reject accounts if the email used is already taken by a different account. That was the idea I was going for with that. I anticipate a one-to-many relationship for Customer_Information and Order_Information. This would allow 1 customer to have multiple orders, while ensuring each order only corresponds to one customer.