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

Paper_lucky_7th #14

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e8c7753
adds card model
courtneycmassey Jun 28, 2021
3f1c894
board model updated with id, title, and owner attributes
danisandiaz Jun 28, 2021
6fdd8f3
Merge pull request #1 from halisasaipulla/card_01
danisandiaz Jun 29, 2021
9c3fe79
Merge pull request #2 from halisasaipulla/board_01
danisandiaz Jun 29, 2021
a052165
models added to app/__init__ file
danisandiaz Jun 29, 2021
6f52b29
corrects spelling of autoincrement
courtneycmassey Jun 29, 2021
f11b756
Merge pull request #3 from halisasaipulla/Courtney-01
danisandiaz Jun 29, 2021
e7b4ee2
board blueprint and route added to init file, board post route begun …
danisandiaz Jun 29, 2021
5c53aac
Merge pull request #4 from halisasaipulla/board_route_01
courtneycmassey Jun 29, 2021
ee56eb6
POST boards route complete
courtneycmassey Jun 29, 2021
a400114
Merge pull request #5 from halisasaipulla/board_route_02
danisandiaz Jun 29, 2021
23d0083
board GET route complete
danisandiaz Jun 29, 2021
38f7503
Merge pull request #6 from halisasaipulla/board_post_01
danisandiaz Jun 29, 2021
5275d8b
Delete migrations directory
danisandiaz Jun 29, 2021
415df01
updated card model with board id FK, added new boards/<board_id>/card…
danisandiaz Jun 29, 2021
688911f
Merge pull request #7 from halisasaipulla/dani_01
courtneycmassey Jun 29, 2021
d440fc6
adds GET route for cards of a board_id
courtneycmassey Jun 29, 2021
6b44218
Added DELETE route for cards/<card_id> endpoint
danisandiaz Jun 29, 2021
6a94d1f
refactored POST card route to set default likes_count to 0
danisandiaz Jun 29, 2021
107c6bb
adds PUT route to cards/<card_id>/like endpoint
courtneycmassey Jun 29, 2021
d74b527
adds route to DELETE board and associated cards
courtneycmassey Jun 30, 2021
5b2301f
adds color attribute to Card model
courtneycmassey Jul 1, 2021
7acf7fe
Merge pull request #8 from halisasaipulla/courtney-02
courtneycmassey Jul 1, 2021
5bb6d1a
updated card model
danisandiaz Jul 1, 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
10 changes: 8 additions & 2 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ def create_app():

# Import models here for Alembic setup
# from app.models.ExampleModel import ExampleModel
from app.models.board import Board
from app.models.card import Card

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

# Register Blueprints here
# from .routes import example_bp
# app.register_blueprint(example_bp)
from .routes import board_bp
app.register_blueprint(board_bp)

from .routes import card_bp
app.register_blueprint(card_bp)


CORS(app)
return app
14 changes: 14 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
from flask import current_app

from app import db

class Board(db.Model):
board_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String)
owner = db.Column(db.String)

def to_dict(self):
return {
"id": self.board_id,
"title": self.title,
"owner": self.owner
}
18 changes: 18 additions & 0 deletions app/models/card.py
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
from flask import current_app

from app import db

class Card(db.Model):
card_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
message = db.Column(db.String)
likes_count = db.Column(db.Integer)
color = db.Column(db.String, default="yellow")
board_id = db.Column(db.Integer, db.ForeignKey('board.board_id'))

def to_dict(self):
return {
"id": self.card_id,
"message": self.message,
"likes_count": self.likes_count,
"color": self.color,
"board_id": self.board_id
}
96 changes: 95 additions & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,98 @@
from flask import Blueprint, request, jsonify, make_response
from app import db
from .models.board import Board
from .models.card import Card

# example_bp = Blueprint('example_bp', __name__)

board_bp = Blueprint("boards", __name__, url_prefix="/boards")
card_bp = Blueprint("cards", __name__, url_prefix="/cards")

@board_bp.route("", methods=["POST"], strict_slashes=False)
def create_board():
request_body=request.get_json()
if "title" in request_body and "owner" in request_body:
new_board = Board(title= request_body["title"],
owner= request_body["owner"])
db.session.add(new_board)
db.session.commit()

return make_response({"board": new_board.to_dict()}, 201)

elif "title" not in request_body:
return make_response({"details": "Title data invalid"}, 400)

elif "owner" not in request_body:
return make_response({"details": "Owner data invalid"}, 400)

@board_bp.route("", methods=["GET"], strict_slashes=False)
def get_boards():
boards = Board.query.all()
boards_response = [board.to_dict() for board in boards]
return make_response(jsonify(boards_response), 200)

@board_bp.route("/<board_id>", methods=["DELETE"], strict_slashes=False)
def remove_board(board_id):
# delete all cards tied to board_id
cards = Card.query.filter_by(board_id=board_id)
if cards:
for card in cards:
db.session.delete(card)

board = Board.query.get(board_id)
if board:
db.session.delete(board)
db.session.commit()
return jsonify({
"details": (f'Board {board.board_id} successfully deleted from Inspiration Board')
}), 200
return "", 404


@board_bp.route("/<board_id>/cards", methods=["POST"], strict_slashes=False)
def add_card_to_board(board_id):
request_body=request.get_json()

if "message" in request_body:
new_card = Card(message= request_body["message"],
color= request_body["color"],
likes_count= 0,
board_id= int(board_id))
db.session.add(new_card)
db.session.commit()

return make_response({"card": new_card.to_dict()},201)

elif "message" not in request_body:
return make_response({"details": "Message data invalid"}, 400)


@board_bp.route("/<board_id>/cards", methods=["GET"], strict_slashes=False)
def get_cards_from_board(board_id):
cards = Card.query.filter_by(board_id=board_id)
if cards:
cards_response = [card.to_dict() for card in cards]
return make_response({"cards": cards_response}, 200)
return make_response("", 200)

@card_bp.route("/<card_id>", methods=["DELETE"], strict_slashes=False)
def remove_card(card_id):
card = Card.query.get(card_id)
if card:
db.session.delete(card)
db.session.commit()
return jsonify({
"details": (f'Card {card.card_id} successfully deleted from Board {card.board_id}')
}), 200
return "", 404

@card_bp.route("/<card_id>/like", methods=["PUT"], strict_slashes=False)
def add_like_to_card(card_id):
card = Card.query.get(card_id)
if card:
card.likes_count = card.likes_count + 1
db.session.commit()
# what is the front end's response formatting preference???
return jsonify({
"details": (f'Card {card.card_id} now has {card.likes_count} likes')
}), 200
return "", 404
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"}
42 changes: 42 additions & 0 deletions migrations/versions/587505944eef_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""empty message

Revision ID: 587505944eef
Revises:
Create Date: 2021-06-29 14:41:02.556951

"""
from alembic import op
import sqlalchemy as sa


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


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('board',
sa.Column('board_id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('title', sa.String(), nullable=True),
sa.Column('owner', sa.String(), nullable=True),
sa.PrimaryKeyConstraint('board_id')
)
op.create_table('card',
sa.Column('card_id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('message', sa.String(), nullable=True),
sa.Column('likes_count', sa.Integer(), nullable=True),
sa.Column('board_id', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['board_id'], ['board.board_id'], ),
sa.PrimaryKeyConstraint('card_id')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('card')
op.drop_table('board')
# ### end Alembic commands ###
Loading