Skip to content

Use Case #2

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

Open
wants to merge 10 commits into
base: main
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
72 changes: 19 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,25 @@
# Introduction
# Requirements

Welcome to the Bloomscape Engineering coding challenge!
To run this app you have to install:
1 Python
2 Node

We know that you're spending plenty of your personal time meeting with our team
and participating in the interview process. With that in mind, this step is
designed to be quick and a way for you to showcase your coding and architecture
skills.
# Installation

We've creating a coding challenge that is aligned to the types of projects and
problems that we see at Bloomscape. We will be reviewing
To install this app
1 Open a terminal
2 Enter the frontend folder and run yarn/npm install
3 Enter the backend folder and run pip install -r requirements.txt

## Problem
To Run this app
1 Open two termianls
2 In the first terminal cd to the backend folder and run python run.py
3 In the second terminal cd to the frontend folder and run npm start or yarn start

Create a [vending machine](https://en.wikipedia.org/wiki/Vending_machine) in
the language of your choice. The vending machine can sell any product that you
wish.

Your project can take the form of either an API or a UI -- you do not have to
implement both!

*Please spend at most 8 hours on this project.*

**Objectives:**

* Represent a basic data model for the vending machine -- consider things like
how to pay and how to receive a product.
* Prototype a simple UI or API endpoints that allows someone to interact with
the machine.
* You are free to use any language and framework that you wish -- we commmonly
use Typescript, JavaScript, PHP, and Python, along with frameworks like
React, Next.js, Flask, and WordPress.
* Please use any boilerplate or starter project that you like -- we want to see
the way that you build applications and are less concerned with your ability
to craft perfect project infrastructures.
* Be ready to talk about your solution - we'll discuss together in your final
technical interview.

**Things you don't need:**

* Both an API and a working UI -- we'd rather see depth than breadth.
* Persistence -- in-memory is totally sufficient.
* Full implementation of the machine -- one or two actions is enough.

## Instructions

* Please fork this repo
* Create pull requests early and often as you work -- you may merge your own
code, but we want to see how you break down the problem
* Ask any questions that you want -- just tag `@Bloomscape-tech-team` in
Github.

## What We're Looking For

* Your ability build a simple application with an open-ended problem description
* Technical skill in a language/framework of your choosing
* How you breakdown problems -- your thought process is as, or more, important
than your solution
# BackEnd

The backend consist of 1 endpoint:
1 GET /api/v1/products -> Returns all the products in the database
2 PUT /api/v1/products -> Add a product -> Required Fields ["uuid": string(36), "name": string(80), "price":float]
3 PATCH /api/v1/products -> Update a product -> Required Fields ["uuid": string(36)] and the fields that you want to update ["name": string(80), "price":float]
3 DELETE /api/v1/products -> Deletes a product -> Required Fields ["uuid": string(36)]
5 changes: 5 additions & 0 deletions backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Flask==2.0.2
Flask-Cors==3.0.10
Flask-RESTful==0.3.9
Flask-SQLAlchemy==2.5.1
SQLAlchemy==1.4.28
4 changes: 4 additions & 0 deletions backend/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from src import app

if __name__ == "__main__":
app.run(debug=True)
30 changes: 30 additions & 0 deletions backend/src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from flask import Flask
from flask_restful import Api
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS

app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

api = Api(app)


@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers',
'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods',
'GET,PUT,POST,PATCH,DELETE')
return response


db = SQLAlchemy(app)

from src.resources.products import Products

api.add_resource(Products, '/api/v1/products',
'/api/v1/products/<string:product_id>')
Binary file added backend/src/__pycache__/__init__.cpython-39.pyc
Binary file not shown.
Binary file added backend/src/__pycache__/app.cpython-39.pyc
Binary file not shown.
Binary file added backend/src/db.sqlite
Binary file not shown.
10 changes: 10 additions & 0 deletions backend/src/models/Products.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from src import db


class Product(db.Model):
uuid = db.Column(db.String(36), primary_key=True, unique=True)
name = db.Column(db.String(80), unique=False)
price = db.Column(db.Float, unique=False)

def __repr__(self):
return f"<Product {self.name}>"
Binary file not shown.
Binary file not shown.
Binary file not shown.
85 changes: 85 additions & 0 deletions backend/src/resources/products.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import json

from flask_restful import Resource, reqparse, abort, fields, marshal_with

from src.models.products import Product
from src import db


products_args = reqparse.RequestParser()

products_args.add_argument(
'uuid', type=str, required=True, help='UUID is required')
products_args.add_argument(
'name', type=str, required=True, help='Name is required')
products_args.add_argument(
'price', type=float, required=True, help='Price is required')

products_args_update = reqparse.RequestParser()

products_args_update.add_argument(
'uuid', type=str, required=True, help='UUID is required')
products_args_update.add_argument(
'name', type=str)
products_args_update.add_argument(
'price', type=float)

resource_fields = {
'uuid': fields.String,
'name': fields.String,
'price': fields.Float
}


def abort_if_product_doesnt_exist(product_id):
product = Product.query.filter_by(uuid=product_id).first()
if not product:
abort(404, message="Product {} doesn't exist".format(product_id))


class Products(Resource):

@marshal_with(resource_fields)
def get(self):
data = Product.query.all()
return data, 200

def put(self):
args = products_args.parse_args()
try:
product = Product(uuid=args['uuid'],
name=args['name'], price=args['price'])
db.session.add(product)
db.session.commit()
return {"created": args}, 201
except(e):
return {"error": e}, 400

def patch(self):
args = products_args_update.parse_args()
abort_if_product_doesnt_exist(args['uuid'])
try:
product = Product.query.filter_by(
uuid=args['uuid']).first()

if args['name']:
product.name = args['name']

if args['price']:
product.price = args['price']

db.session.commit()

return {"updated": product.uuid}, 200
except Exception as e:
return {"error": e}, 400

def delete(self, product_id):
abort_if_product_doesnt_exist(product_id)
try:
product = Product.query.filter_by(uuid=product_id).first()
db.session.delete(product)
db.session.commit()
return {"deleted": product_id}, 200
except Exception as e:
return {"error": e}, 400
19 changes: 19 additions & 0 deletions backend/src/test/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import requests
import uuid

BASE = "http://127.0.0.1:5000/api/v1/products"

responseGET = requests.get(BASE)
print(responseGET.json())

responsePUT = requests.put(
BASE, json={"uuid": str(uuid.uuid4()), "name": "test", "price": 1.0})
print(responsePUT.json())

responsePATCH = requests.patch(
BASE, json={"uuid": str(uuid.uuid4()), "name": "test", "price": 1.0})
print(responsePATCH.json())

responseDELETE = requests.delete(
BASE + "/" + str(uuid.uuid4()))
print(responseDELETE.json())
24 changes: 24 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
70 changes: 70 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `yarn start`

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.

The page will reload when you make changes.\
You may also see any lint errors in the console.

### `yarn test`

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

### `yarn build`

Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `yarn eject`

**Note: this is a one-way operation. Once you `eject`, you can't go back!**

If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.

You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).

### Code Splitting

This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)

### Analyzing the Bundle Size

This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)

### Making a Progressive Web App

This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)

### Advanced Configuration

This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)

### Deployment

This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)

### `yarn build` fails to minify

This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
41 changes: 41 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^13.2.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-icons": "^4.3.1",
"react-router-dom": "^6.2.1",
"react-scripts": "5.0.0",
"uuid": "^8.3.2",
"web-vitals": "^2.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Binary file added frontend/public/favicon.ico
Binary file not shown.
12 changes: 12 additions & 0 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vending Machine</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Loading