Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
67cc5df
created blueprint and registered in init file
Infernormal Oct 18, 2021
97a7024
Added Planet class and list of planet instances
roslynm Oct 18, 2021
63c6c05
created endpoint for planets
Infernormal Oct 18, 2021
ee4a36a
Added route for single planet response
roslynm Oct 18, 2021
05f4785
Additional picture info added to class
roslynm Oct 18, 2021
c2fbe5f
Added picture rendering and html templates
roslynm Oct 18, 2021
d822457
created model and set up database
Infernormal Oct 25, 2021
73bf728
Added route for handle plantes
roslynm Oct 25, 2021
1799c41
added id specific route
Infernormal Oct 25, 2021
25d4594
Added post planet functionality, and picture routes, and added .txt f…
roslynm Oct 25, 2021
d833244
Added PUT and PATCH functionality to handle_planet()
roslynm Oct 26, 2021
80a2f72
added delete request and created helper func to_dict
Infernormal Oct 26, 2021
e70a696
typo and added lines for readability
Infernormal Oct 26, 2021
03499ba
updated solution for patch
Infernormal Oct 26, 2021
fe8ee9b
sanitize func and 404s updates
Infernormal Oct 27, 2021
2c8e489
Updated functions with query params
roslynm Oct 27, 2021
de29dec
added order by and filter by has moons
Infernormal Oct 27, 2021
7f6eb66
added tests
Infernormal Oct 28, 2021
9c87859
added Procfile
roslynm Nov 3, 2021
587834d
added .env file, and new migrations folder
roslynm Nov 3, 2021
7a9eff0
updated Procfile
roslynm Nov 3, 2021
cb47a25
updated Procfile again
roslynm Nov 3, 2021
fb7edff
added gunicorn to requirements.txt
roslynm Nov 3, 2021
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
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: gunicorn 'app:create_app()'
25 changes: 25 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from dotenv import load_dotenv
import os

db = SQLAlchemy()
migrate = Migrate()
load_dotenv()

def create_app(test_config=None):
app = Flask(__name__)

if not test_config:
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get(
"SQLALCHEMY_DATABASE_URI")
else:
app.config["TESTING"] = True
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
"SQLALCHEMY_TEST_DATABASE_URI")
Comment on lines +14 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of env variables!


from app.models.planet import Planet

db.init_app(app)
migrate.init_app(app, db)

from .routes import planets_bp
app.register_blueprint(planets_bp)

return app
Empty file added app/models/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions app/models/planet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from app import db

class Planet(db.Model):
__tablename__ = "Planets"
id = db.Column(db.Integer,primary_key=True,autoincrement = True)
name = db.Column(db.String)
diameter = db.Column(db.String)
moons = db.Column(db.Boolean)
picture = db.Column(db.String)

def to_dict(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good helper method!

return ({"id": self.id,
"name": self.name,
"diameter": self.diameter,
"moons": self.moons,
"picture": self.picture})
55 changes: 55 additions & 0 deletions app/models/planet_info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "Mercury",
"diameter":"Diameter: 3,031 miles (4,878 km)",
"moons": false,
"picture":"https://cdn.mos.cms.futurecdn.net/oU94fqcyf9HzQc59wJyaHN-970-80.jpg"
}

{
"name": "Venus",
"diameter": "Diameter: 7,521 miles (12,104 km)",
"moons": false,
"picture": "https://cdn.mos.cms.futurecdn.net/KhHofvaDG73pypCEzyLuab-970-80.png"
}

{
"name": "Earth",
"diameter": "Diameter: 7,926 miles (12,760 km)",
"moons": true,
"picture": "https://cdn.mos.cms.futurecdn.net/4aeTmiqCqpRKuFc8tkDcmm-970-80.jpg"
}

{
"name": "Mars",
"diameter": "Diameter: 4,217 miles (6,787 km)",
"moons": true,
"picture": "https://cdn.mos.cms.futurecdn.net/tQUhJUq9GXqMfZXjGYdw8c-970-80.jpg"
}

{
"name": "Jupiter",
"diameter":"Diameter: 86,881 miles (139,822 km)",
"moons": true,
"picture":"https://cdn.mos.cms.futurecdn.net/WyxFYsiUAQAgU4peSSoBNZ-970-80.png"
}

{
"name": "Saturn",
"diameter":"Diameter: 74,900 miles (120,500 km)",
"moons": true,
"picture":"https://cdn.mos.cms.futurecdn.net/bDVqRSjnbY9jMyVPmStUBY-970-80.png"
}

{
"name": "Uranus",
"diameter":"Diameter: 31,763 miles (51,120 km)",
"moons": true,
"picture":"https://cdn.mos.cms.futurecdn.net/kZXxHS85dDgVEAviQrM2KW-970-80.jpg"
}

{
"name": "Neptune",
"diameter":"Diameter: 30,775 miles (49,530 km)",
"moons": true,
"picture":"https://cdn.mos.cms.futurecdn.net/KW2AU72GRriUXQvsn5jAbg-970-80.jpg"
}
137 changes: 136 additions & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,137 @@
from flask import Blueprint
from flask import Blueprint, jsonify, render_template, make_response, request, abort
from app import db
from app.models.planet import Planet


planets_bp = Blueprint("planets_bp", __name__,url_prefix="/planets")


@planets_bp.route("", methods = ["GET"])
def handle_planets():
Comment on lines +9 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Like the Query params

planets_response = []

if request.args.get("name"):
planets = Planet.query.filter_by(name=request.args.get("name"))

elif request.args.get("has_moons"):
planets = Planet.query.filter(Planet.moons == request.args.get("has_moons"))

elif request.args.get("order_by") == "name":
planets = Planet.query.order_by(Planet.name)

else:
planets = Planet.query.all()
for planet in planets:
planets_response.append(planet.to_dict())

return jsonify(planets_response), 200


@planets_bp.route("/<planet_id>", methods=["GET", "PATCH", "PUT", "DELETE"])
def handle_planet(planet_id):
if not planet_id.isnumeric():
return { "Error": f"{planet_id} must be numeric."}, 404

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An argument can be made for this to be a 400 error as opposed to 404.

planet_id = int(planet_id)
planet = Planet.query.get(planet_id)
if not planet:
return { "Error": f"Planet {planet_id} was not found"}, 404

elif request.method == "GET":
return (planet.to_dict()),200

elif request.method == "PATCH":
form_data = request.get_json()
sanitize_data(form_data)
if 'name' in form_data:
planet.name = request.json['name']
if 'diameter' in form_data:
planet.diameter = request.json['diameter']
if 'moons' in form_data:
planet.moons = request.json['moons']
if 'picture' in form_data:
planet.picture = request.json['picture']

db.session.commit()

return make_response(f"Planet #{planet.id} successfully updated")

elif request.method == "PUT":
form_data = request.get_json()
sanitize_data(form_data)
planet.name = form_data["name"]
planet.diameter = form_data["diameter"]
planet.moons = form_data["moons"]
planet.picture = form_data["picture"]

db.session.commit()

return make_response(f"Planet #{planet.id} successfully updated")

elif request.method == "DELETE":
db.session.delete(planet)
db.session.commit()

return {
"message": f"Planet with title {planet.name} has been deleted"
}, 200


@planets_bp.route("", methods=["POST"])
def create_planet():
request_data = request.get_json()
sanitize_data(request_data)

if "name" not in request_data or "moons" not in request_data \
or "diameter" not in request_data or "picture" not in request_data:

return jsonify({"message": "Missing data"}), 400

new_planet = Planet(name=request_data["name"], diameter=request_data["diameter"],
moons=request_data["moons"], picture=request_data["picture"])

db.session.add(new_planet)
db.session.commit()

return f"Planet {new_planet.name} created", 201

@planets_bp.route("/picturesummary", methods=["GET"])
def handle_planet_summary_params():
Comment on lines +97 to +98

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice custom route and use of render_template

if request.args.get("name"):
planets = Planet.query.filter_by(name=request.args.get("name"))
for planet in planets:
if planet.moons == True:
moon = "Yes"
else:
moon = "No"
return render_template('planet_summary.html',
url=planet.picture,
title=planet.name,
diameter=planet.diameter,
moon=moon)

@planets_bp.route("/picturesummary/<planet_id>", methods=["GET"])
def handle_planet_summary(planet_id):
planet = Planet.query.get(planet_id)
if planet.moons == True:
moon = "Yes"
else:
moon = "No"

return render_template('planet_summary.html',
url=planet.picture,
title=planet.name,
diameter=planet.diameter,
moon=moon)
Comment on lines +120 to +124

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh well!



def sanitize_data(input_data):
data_types = {"name":str, "diameter":str, "moons":bool, "picture":str}
for name, val_type in data_types.items():
try:
assert val_type==type(input_data[name])
print(name,type(input_data[name]))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print isn't needed

Suggested change
print(name,type(input_data[name]))


except Exception as e:
print(e)
abort(400, "Bad Data")
return input_data
9 changes: 9 additions & 0 deletions app/templates/planet_picture.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<html>
<head>
</head>

<body>
<img src="{{ url }}">
</body>

</html>
15 changes: 15 additions & 0 deletions app/templates/planet_summary.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<html>
<head>
</head>

<body>
<h1>{{title}}</h1>
<br>
<i>{{diameter}}</i>
<br>
<i>Moon: {{moon}}</i>
<br>
<img src="{{ url }}">
</body>

</html>
Comment on lines +1 to +15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

1 change: 1 addition & 0 deletions migrations/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Generic single-database configuration.
45 changes: 45 additions & 0 deletions migrations/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# A generic, single database configuration.

[alembic]
# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
Loading