Skip to content

Commit ac19a63

Browse files
initial commit
0 parents  commit ac19a63

18 files changed

+290
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
__pycache__/
3+
*.pyc

Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: uwsgi uwsgi.ini

app.py

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import os
2+
3+
from flask import Flask
4+
from flask_restful import Api
5+
from flask_jwt import JWT
6+
7+
from security import authenticate, identity
8+
from resources.user import UserRegister
9+
from resources.item import Item, ItemList
10+
from resources.store import Store, StoreList
11+
12+
app = Flask(__name__)
13+
14+
app.config['DEBUG'] = True
15+
16+
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///data.db')
17+
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
18+
app.secret_key = 'jose'
19+
api = Api(app)
20+
21+
jwt = JWT(app, authenticate, identity) # /auth
22+
23+
api.add_resource(Store, '/store/<string:name>')
24+
api.add_resource(Item, '/item/<string:name>')
25+
api.add_resource(ItemList, '/items')
26+
api.add_resource(StoreList, '/stores')
27+
28+
api.add_resource(UserRegister, '/register')
29+
30+
if __name__ == '__main__':
31+
from db import db
32+
db.init_app(app)
33+
34+
if app.config['DEBUG']:
35+
@app.before_first_request
36+
def create_tables():
37+
db.create_all()
38+
39+
app.run(port=5000)

db.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from flask_sqlalchemy import SQLAlchemy
2+
3+
db = SQLAlchemy()

models/__init__.py

Whitespace-only changes.

models/item.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
from db import db
2+
3+
class ItemModel(db.Model):
4+
__tablename__ = 'items'
5+
6+
id = db.Column(db.Integer, primary_key=True)
7+
name = db.Column(db.String(80))
8+
price = db.Column(db.Float(precision=2))
9+
10+
store_id = db.Column(db.Integer, db.ForeignKey('stores.id'))
11+
store = db.relationship('StoreModel')
12+
13+
def __init__(self, name, price, store_id):
14+
self.name = name
15+
self.price = price
16+
self.store_id = store_id
17+
18+
def json(self):
19+
return {'name': self.name, 'price': self.price}
20+
21+
@classmethod
22+
def find_by_name(cls, name):
23+
return cls.query.filter_by(name=name).first()
24+
25+
def save_to_db(self):
26+
db.session.add(self)
27+
db.session.commit()
28+
29+
def delete_from_db(self):
30+
db.session.delete(self)
31+
db.session.commit()

models/store.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from db import db
2+
3+
class StoreModel(db.Model):
4+
__tablename__ = 'stores'
5+
6+
id = db.Column(db.Integer, primary_key=True)
7+
name = db.Column(db.String(80))
8+
9+
items = db.relationship('ItemModel', lazy='dynamic')
10+
11+
def __init__(self, name):
12+
self.name = name
13+
14+
def json(self):
15+
return {'name': self.name, 'items': [item.json() for item in self.items.all()]}
16+
17+
@classmethod
18+
def find_by_name(cls, name):
19+
return cls.query.filter_by(name=name).first()
20+
21+
def save_to_db(self):
22+
db.session.add(self)
23+
db.session.commit()
24+
25+
def delete_from_db(self):
26+
db.session.delete(self)
27+
db.session.commit()

models/user.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import sqlite3
2+
from db import db
3+
4+
class UserModel(db.Model):
5+
__tablename__ = 'users'
6+
7+
id = db.Column(db.Integer, primary_key=True)
8+
username = db.Column(db.String(80))
9+
password = db.Column(db.String(80))
10+
11+
def __init__(self, username, password):
12+
self.username = username
13+
self.password = password
14+
15+
def save_to_db(self):
16+
db.session.add(self)
17+
db.session.commit()
18+
19+
@classmethod
20+
def find_by_username(cls, username):
21+
return cls.query.filter_by(username=username).first()
22+
23+
@classmethod
24+
def find_by_id(cls, _id):
25+
return cls.query.filter_by(id=_id).first()

readme.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Stores REST Api
2+
3+
This is built with Flask, Flask-RESTful, Flask-JWT, and Flask-SQLAlchemy.
4+
5+
Deployed on Heroku.

requirements.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Flask
2+
Flask-RESTful
3+
Flask-JWT
4+
Flask-SQLAlchemy
5+
uwsgi
6+
psycopg2

resources/__init__.py

Whitespace-only changes.

resources/item.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from flask_restful import Resource, reqparse
2+
from flask_jwt import jwt_required
3+
from models.item import ItemModel
4+
5+
class Item(Resource):
6+
parser = reqparse.RequestParser()
7+
parser.add_argument('price',
8+
type=float,
9+
required=True,
10+
help="This field cannot be left blank!"
11+
)
12+
parser.add_argument('store_id',
13+
type=int,
14+
required=True,
15+
help="Every item needs a store id."
16+
)
17+
18+
@jwt_required()
19+
def get(self, name):
20+
item = ItemModel.find_by_name(name)
21+
if item:
22+
return item.json()
23+
return {'message': 'Item not found'}, 404
24+
25+
def post(self, name):
26+
if ItemModel.find_by_name(name):
27+
return {'message': "An item with name '{}' already exists.".format(name)}, 400
28+
29+
data = Item.parser.parse_args()
30+
31+
item = ItemModel(name, **data)
32+
33+
try:
34+
item.save_to_db()
35+
except:
36+
return {"message": "An error occurred inserting the item."}, 500
37+
38+
return item.json(), 201
39+
40+
def delete(self, name):
41+
item = ItemModel.find_by_name(name)
42+
if item:
43+
item.delete_from_db()
44+
45+
return {'message': 'Item deleted'}
46+
47+
def put(self, name):
48+
data = Item.parser.parse_args()
49+
50+
item = ItemModel.find_by_name(name)
51+
52+
if item is None:
53+
item = ItemModel(name, **data)
54+
else:
55+
item.price = data['price']
56+
57+
item.save_to_db()
58+
59+
return item.json()
60+
61+
62+
class ItemList(Resource):
63+
def get(self):
64+
return {'items': [x.json() for x in ItemModel.query.all()]}

resources/store.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from flask_restful import Resource, reqparse
2+
from models.store import StoreModel
3+
4+
class Store(Resource):
5+
def get(self, name):
6+
store = StoreModel.find_by_name(name)
7+
if store:
8+
return store.json()
9+
return {'message': 'Store not found'}, 404
10+
11+
def post(self, name):
12+
if StoreModel.find_by_name(name):
13+
return {'message': "A store with name '{}' already exists.".format(name)}, 400
14+
15+
store = StoreModel(name)
16+
try:
17+
store.save_to_db()
18+
except:
19+
return {"message": "An error occurred creating the store."}, 500
20+
21+
return store.json(), 201
22+
23+
def delete(self, name):
24+
store = StoreModel.find_by_name(name)
25+
if store:
26+
store.delete_from_db()
27+
28+
return {'message': 'Store deleted'}
29+
30+
class StoreList(Resource):
31+
def get(self):
32+
return {'stores': [store.json() for store in StoreModel.query.all()]}

resources/user.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import sqlite3
2+
from flask_restful import Resource, reqparse
3+
from models.user import UserModel
4+
5+
class UserRegister(Resource):
6+
7+
parser = reqparse.RequestParser()
8+
parser.add_argument('username',
9+
type=str,
10+
required=True,
11+
help="This field cannot be blank."
12+
)
13+
parser.add_argument('password',
14+
type=str,
15+
required=True,
16+
help="This field cannot be blank."
17+
)
18+
19+
def post(self):
20+
data = UserRegister.parser.parse_args()
21+
22+
if UserModel.find_by_username(data['username']):
23+
return {"message": "A user with that username already exists"}, 400
24+
25+
user = UserModel(**data)
26+
user.save_to_db()
27+
28+
return {"message": "User created successfully."}, 201

run.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from app import app
2+
from db import db
3+
4+
db.init_app(app)
5+
6+
@app.before_first_request
7+
def create_tables():
8+
db.create_all()

runtime.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python-3.7.5

security.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from werkzeug.security import safe_str_cmp
2+
from models.user import UserModel
3+
4+
def authenticate(username, password):
5+
user = UserModel.find_by_username(username)
6+
if user and safe_str_cmp(user.password, password):
7+
return user
8+
9+
def identity(payload):
10+
user_id = payload['identity']
11+
return UserModel.find_by_id(user_id)

uwsgi.ini

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[uwsgi]
2+
http-socket = :$(PORT)
3+
master = true
4+
die-on-term = true
5+
module = run:app
6+
memory-report = true

0 commit comments

Comments
 (0)