Grey Market Labs assessment

This commit is contained in:
2022-04-27 22:01:08 -04:00
parent 01926a3cca
commit 4ab043c3a9
8 changed files with 256 additions and 2 deletions

BIN
Developer Evaluation.docx Normal file

Binary file not shown.

19
Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM node:latest
# Set working directoy
WORKDIR /usr/src/app
# Copy dependencies and install
COPY package*.json ./
RUN npm install
# Copy code
COPY *.js ./
# Run the app
EXPOSE 3000
COPY start.sh .
RUN chmod 777 start.sh
CMD ./start.sh

3
Makefile Normal file
View File

@@ -0,0 +1,3 @@
test: app.js package.json
sudo docker build . -t paul/greymarket
sudo docker run -it -p 4916:3000 paul/greymarket

View File

@@ -1,3 +1,76 @@
# greymarketlabs-assignment
# Running the service
## Pre-Reqs
* Access to the interenet
* Docker environment installed with proper user permissions
## Running
* This will use port 4916, if that is not available modify the Makefile
* Run `make`
## Stopping
* Type `exit`
## Testing
* Run `bash ./test.sh` in a seperate window on the same machine
# API Description
## Setting Persona
GET request to /set_persona with the following properties
* persona_id: integer (if not unique it will override a previous persona)
* first_name: string first name of persona
* last_name: string last name of persona
* interest_list: string comma seperated list of interests
* lat: floating point latitude of location
* lon: floating point longitude of location
This will return a json formatted string of the values you set
## Getting persona
GET request to /get_persona with the following propertie
* persona_id: integer id (error will occur if it does not exist)
This will return a JSON in the following format
* id: integer persona id
* first_name: string first name
* last_name: string last name
* interest_list: comma seperated string of interests
* latitude: floating point latitude
* longitude: floating point longitude
* city: string city
* state: string state
* temperature: current temperature in fahrenheit
# Further Questions
## A
I was not able to complete every aspect of this assignment. I few things I would have liked to accomplish in addition were:
* Proper error checking
* Currently it'll just fail out if bad inputs are given. I would have liked to have it error gracefully with proper error codes
* Clean up the code
* There are some odd variable names and no comments
* Several variables in the API itself change from input to output, I would have liked to make those the same
* Better id handling
* Have additional ways to determine what the next un-assigned ID would be
* Have a better way when getting the information that an ID doesn't exist
* Better testing
* Create a little more robust testing
* Temperature
* I grabbed the first temperature returned, rather than the current. It isn't too far off, but would have like to get the actual current temperature.
## B
Potential issues include
* Poor error handling, the app will crash on bad input
* Provide more rubust intput checking with error code/string returns
* Interest list handling
* Right now it is just a comma seperated list
* I would have liked to have a seperate table of interests, then the returned json could have been an array list. This would have provided better access for the front end
* Repeat/Unknown IDs
* A repeat ID will overwrite perviously set values, this was a choice, but the API should have an update vs new option
* There could also be a way to not give an ID and the next ID is reaturned to the front end
* Unknown IDs on get are not handled and will cause a crash, there should be an error message returned
## C
Possible security issues are:
* If anyone has arbetrary access they will be able to get all the persona information, this should be locked down to only authorized users
* Overloading the memory with large values, there is no limit to the length of the strings, thus someone could overwhelm the system by putting in too long of strings
Assignment for Grey Market Labs

140
app.js Normal file
View File

@@ -0,0 +1,140 @@
const util = require('util');
const express = require('express');
const sqlite = require('sqlite3');
const request = require('sync-request');
const app = express();
const persona_db = new sqlite.Database('./counter_persona.db', (err) => {
if(err) {
console.log(err.message);
exit(1);
}
persona_db.exec(`
CREATE TABLE IF NOT EXISTS persona (
id unsigned int primary key not null,
first_name text not null,
last_name text not null,
interest_list text not null,
latitude real not null,
longitude real not null
);
`);
});
function on_err(err_str, err_code) {
console.log(err_str);
return {
"err": err_str,
"code": err_code,
};
};
function insert_update_persona(user_params) {
persona_db.get("SELECT * FROM persona WHERE id = ?", [user_params.persona_id], (err, row) => {
if(row == undefined) {
persona_db.run(`
insert into persona
(id, first_name, last_name, interest_list, latitude, longitude)
values (?, ?, ?, ?, ?, ?)
`, [
user_params.persona_id,
user_params.first_name,
user_params.last_name,
user_params.interest_list,
user_params.lat,
user_params.lon
], (err) => {
if(err) {
console.log(err.message);
}
});
} else {
persona_db.run(`
UPDATE persona SET
first_name = ?,
last_name = ?,
interest_list = ?,
latitude = ?,
longitude = ?
WHERE id = ?
`, [
user_params.first_name,
user_params.last_name,
user_params.interest_list,
user_params.lat,
user_params.lon,
user_params.persona_id
], (err) => {
if(err) {
console.log(err.message);
}
});
}
});
};
function get_weather(user_params) {
my_headers = {headers: {'user-agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36"}};
weather_url = util.format("https://api.weather.gov/points/%d,%d", user_params.latitude, user_params.longitude);
data = request('GET', weather_url, my_headers);
data = JSON.parse(data.getBody());
user_params.city = data.properties.relativeLocation.properties.city;
user_params.state = data.properties.relativeLocation.properties.state;
data = request('GET', data.properties.forecast, my_headers);
data = JSON.parse(data.getBody());
user_params.temperature = data.properties.periods[0].temperature;
return user_params;
};
app.get('/get_persona', function(req, res) {
// Gather params
user_params = {
persona_id: Number(req.query.persona_id),
};
persona_db.get("SELECT * FROM persona WHERE id = ?", [user_params.persona_id], (err, row) => {
if(err) {
console.error(err.message);
}
user_params = row;
user_params = get_weather(user_params);
console.log(user_params);
res.send(user_params);
});
});
app.get('/set_persona', function(req, res) {
// Gather params
user_params = {
persona_id: parseInt(req.query.persona_id),
first_name: req.query.first_name,
last_name: req.query.last_name,
interest_list: req.query.interest_list,
lat: Number(req.query.lat),
lon: Number(req.query.lon),
};
// Verify params
for(const key in user_params) {
if(user_params[key] == undefined) {
res.send(on_err(util.format('%s must be defined', key), 1));
return;
}
}
insert_update_persona(user_params);
res.send(user_params);
});
app.listen(3000, () => console.log('Server ready'));

12
package.json Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "greymarket",
"version": "1.0",
"description": "Grey Market assessment, tracking profiles",
"author": "Paul Halvorsen <pmghalvorsen@gmail.com>",
"dependencies": {
"express": "",
"util": "",
"sqlite3": "",
"sync-request": ""
}
}

3
start.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
node app.js &
/bin/bash

4
test.sh Normal file
View File

@@ -0,0 +1,4 @@
echo
curl "http://localhost:4916/set_persona?persona_id=1&first_name=hello&last_name=world&interest_list=a,b,c&lat=39.2673&lon=-76.7983"
curl "http://localhost:4916/get_persona?persona_id=1"
echo