Skip to content
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

Cedar - Jacy & Kit #15

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c5a9bfc
Adds class Planet to routes.py
KitSutliff Oct 18, 2021
eb71eb6
Add get all functions and registers blueprint class
KitSutliff Oct 18, 2021
3d7bffd
Adds get_planet function to routes.py
KitSutliff Oct 18, 2021
9cf827e
debug adds missing carrots to routes.py
KitSutliff Oct 18, 2021
39c4dd7
fixed bug in routes.py; changed planet_id to planet in get_planet fun…
jacyyang04 Oct 18, 2021
6d98074
add comment about local host url
jacyyang04 Oct 18, 2021
b42cc8f
add to_json instance method and removed var(planet)
jacyyang04 Oct 22, 2021
0b775b2
delete spacing
jacyyang04 Oct 22, 2021
45c7886
replaces planet class in app with planet model in app.models.
KitSutliff Oct 25, 2021
a29a3af
moves models folder from pycache to app under SOLAR-SYSTEM-API.
KitSutliff Oct 25, 2021
9a0acd4
updates planet.py class in models to do stuff better... like.. with t…
KitSutliff Oct 25, 2021
3c2ff79
we migrated models and updated routes.
KitSutliff Oct 25, 2021
54be1bb
updates routes to fix bug
KitSutliff Oct 25, 2021
7884f06
changed query.all to query.get for get_planet function
jacyyang04 Oct 25, 2021
7d7a32f
made request_body local var
jacyyang04 Oct 26, 2021
2628ed7
minor space changes
jacyyang04 Oct 26, 2021
c737a22
Adds 'update' and 'delete' methods to routes.py
KitSutliff Oct 26, 2021
f1e3085
Started refactoring source code
jacyyang04 Oct 27, 2021
c673c70
add 404 error code
jacyyang04 Oct 27, 2021
778f1ef
refactor all functions
jacyyang04 Oct 27, 2021
7caf8d2
update function names
jacyyang04 Oct 27, 2021
08d0db3
add error codes for return statements
jacyyang04 Oct 27, 2021
9bd9398
add query search routes
jacyyang04 Oct 27, 2021
45f4ace
add purge
jacyyang04 Oct 27, 2021
edf2bfc
fix bugs in create_planets function
jacyyang04 Oct 28, 2021
351d71d
update create_planets function
jacyyang04 Oct 28, 2021
8aafbfb
set up environmental vars
jacyyang04 Oct 28, 2021
42e0d2c
set up test files
jacyyang04 Oct 28, 2021
19ece10
add test routes
jacyyang04 Oct 28, 2021
54abab4
update
jacyyang04 Oct 28, 2021
49302c3
fix test bugs
jacyyang04 Oct 28, 2021
67b3bf4
fix test bugs, update return statement
jacyyang04 Oct 28, 2021
9af523e
change error code
jacyyang04 Oct 28, 2021
663d89a
finalized comments
jacyyang04 Oct 28, 2021
8b5fa84
add procfile
jacyyang04 Nov 3, 2021
b54163c
add gunicorn to requirements.txt
jacyyang04 Nov 3, 2021
ca7eb00
adds Procfile
KitSutliff Nov 3, 2021
2e2e587
actually adds Procfile, but for real this time
KitSutliff 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()'
24 changes: 24 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
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__)

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

if not test_config:
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_DATABASE_URI')
else:
app.config["TESTING"] = True
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('SQLALCHEMY_TEST_DATABASE_URI')

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

#import models
from app.models.planet import Planet

from .routes import planets_bp
app.register_blueprint(planets_bp)

return app
1 change: 1 addition & 0 deletions app/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#"we don't need to do anything" - jacy
17 changes: 17 additions & 0 deletions app/models/planet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from app import db
#"This is where we CREATE OUR PLANET! (class)"

class Planet(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String)
description = db.Column(db.String)
xenomorphs = db.Column(db.Boolean, default=False)

def to_json(self):
json_dict = {
"id": self.id,
"name": self.name,
"description": self.description,
"xenomorphs": self.xenomorphs

Choose a reason for hiding this comment

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

Oh no!

}
return json_dict
97 changes: 96 additions & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,97 @@
from flask import Blueprint

from flask import Blueprint, jsonify, make_response, request, abort
from app.models.planet import Planet
from app import db


# Global Vars
planets_bp = Blueprint("planets_bp", __name__, url_prefix="/planets")


# Helper Functions
def get_planet(planet_id):
"""Get planet by planet_id or return 404"""
return Planet.query.get_or_404(planet_id, description="Planet does not exist.")


# Routes
@planets_bp.route("", methods=["POST"])
def create_planets():
"""Create new planet in database."""
request_body = request.get_json()

if request_body is None:
return make_response("Invalid Request", 400)

if "name" not in request_body or "description" not in request_body or "xenomorphs" not in request_body:
return make_response("Invalid Request", 400)

new_planet = Planet(
name=request_body['name'],
description=request_body['description'],
xenomorphs=request_body['xenomorphs']
)

# add and commit new_planet to database
db.session.add(new_planet)
db.session.commit()

return make_response(f"Your planet, {new_planet.name}, has been created.", 201)


@planets_bp.route("", methods=["GET"])
def read_all_planets():
"""Get all planets or get planets with query params"""
name_query = request.args.get("name")
xenomorphs_query = request.args.get("xenomorphs")

##---partial functionality; would like to discuss---##
if name_query:
planets = Planet.query.filter_by(name=name_query)
elif xenomorphs_query:
planets = Planet.query.filter_by(xenomorphs=xenomorphs_query)
##---END---##
Comment on lines +48 to +53

Choose a reason for hiding this comment

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

else:
planets = Planet.query.all()

planets_response = []

for planet in planets:
planets_response.append(planet.to_json())

return jsonify(planets_response)


@planets_bp.route("/<planet_id>", methods=["GET"])
def read_a_planet(planet_id):
"""Get planet with planet_id"""
planet = get_planet(planet_id)
return planet.to_json()

@planets_bp.route("/<planet_id>", methods=["PATCH"])
def update_a_planet(planet_id):
"""Update data for planet with planet_id in database"""
request_body = request.get_json()
planet = get_planet(planet_id)

if "id" in request_body:
planet.id = request_body["id"]
if "name" in request_body:
planet.name = request_body["name"]
if "description" in request_body:
planet.description = request_body["description"]
if "xenomorphs" in request_body:
planet.xenomorphs = request_body["xenomorphs"]

db.session.commit()
return make_response(f"Planet {planet.id} has been updated.", 201)


@planets_bp.route("/<planet_id>", methods=["DELETE"])
def delete_a_planet(planet_id):
"""Delete planet with planet_id in database"""
planet = get_planet(planet_id)

db.session.delete(planet)
db.session.commit()
return make_response(f"Planet #{planet_id} successfully destroyed.", 200)
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
96 changes: 96 additions & 0 deletions migrations/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from __future__ import with_statement

import logging
from logging.config import fileConfig

from sqlalchemy import engine_from_config
from sqlalchemy import pool
from flask import current_app

from alembic import context

# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config

# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
logger = logging.getLogger('alembic.env')

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
config.set_main_option(
'sqlalchemy.url',
str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%'))
target_metadata = current_app.extensions['migrate'].db.metadata

# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.


def run_migrations_offline():
"""Run migrations in 'offline' mode.

This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.

Calls to context.execute() here emit the given string to the
script output.

"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url, target_metadata=target_metadata, literal_binds=True
)

with context.begin_transaction():
context.run_migrations()


def run_migrations_online():
"""Run migrations in 'online' mode.

In this scenario we need to create an Engine
and associate a connection with the context.

"""

# this callback is used to prevent an auto-migration from being generated
# when there are no changes to the schema
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
def process_revision_directives(context, revision, directives):
if getattr(config.cmd_opts, 'autogenerate', False):
script = directives[0]
if script.upgrade_ops.is_empty():
directives[:] = []
logger.info('No changes in schema detected.')

connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=target_metadata,
process_revision_directives=process_revision_directives,
**current_app.extensions['migrate'].configure_args
)

with context.begin_transaction():
context.run_migrations()


if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
24 changes: 24 additions & 0 deletions migrations/script.py.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""${message}

Revision ID: ${up_revision}
Revises: ${down_revision | comma,n}
Create Date: ${create_date}

"""
from alembic import op
import sqlalchemy as sa
${imports if imports else ""}

# revision identifiers, used by Alembic.
revision = ${repr(up_revision)}
down_revision = ${repr(down_revision)}
branch_labels = ${repr(branch_labels)}
depends_on = ${repr(depends_on)}


def upgrade():
${upgrades if upgrades else "pass"}


def downgrade():
${downgrades if downgrades else "pass"}
34 changes: 34 additions & 0 deletions migrations/versions/c888984465f3_adds_planet_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""adds planet model

Revision ID: c888984465f3
Revises:
Create Date: 2021-10-25 14:35:56.579309

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'c888984465f3'
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('planet',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('description', sa.String(), nullable=True),
sa.Column('xenomorphs', sa.Boolean(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('planet')
# ### end Alembic commands ###
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
alembic==1.5.4
attrs==21.2.0
autopep8==1.5.5
certifi==2020.12.5
chardet==4.0.0
click==7.1.2
Flask==1.1.2
Flask-Migrate==2.6.0
Flask-SQLAlchemy==2.4.4
gunicorn==20.1.0
idna==2.10
iniconfig==1.1.1
itsdangerous==1.1.0
Jinja2==2.11.3
Mako==1.1.4
MarkupSafe==1.1.1
packaging==21.0
pluggy==1.0.0
psycopg2-binary==2.8.6
py==1.10.0
pycodestyle==2.6.0
pyparsing==3.0.3
pytest==6.2.5
python-dateutil==2.8.1
python-dotenv==0.15.0
python-editor==1.0.4
Expand Down
Empty file added tests/__init__.py
Empty file.
Loading