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

Sharks - Jande, Ivana & Emily #23

Open
wants to merge 17 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
19 changes: 16 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,35 @@
load_dotenv()


def create_app():
def create_app(test_config=None):
app = Flask(__name__)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
"SQLALCHEMY_DATABASE_URI")
if test_config is None:
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")


# 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.board_routes import board_bp
app.register_blueprint(board_bp)

from .routes.card_routes import card_bp
app.register_blueprint(card_bp)

CORS(app)
return app
25 changes: 25 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,26 @@
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)
cards = db.relationship("Card", back_populates="board", lazy=True)

def to_json(self):
return {
"board_id": self.board_id,
"title": self.title,
"owner": self.owner,
# "cards": self.cards
# do we want to return an empty list of cards?
}

@classmethod
def create(cls, request_body):
return cls(title=request_body["title"], owner=request_body["owner"])

# UPDATE BOARD
def update(self, request_body):
self.title = request_body["title"]
self.owner = request_body["owner"]
28 changes: 28 additions & 0 deletions app/models/card.py
Original file line number Diff line number Diff line change
@@ -1 +1,29 @@
from app import db
from flask import make_response, abort


class Card(db.Model):
card_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
message = db.Column(db.String)
like_count = db.Column(db.Integer)
board_id = db.Column(db.Integer, db.ForeignKey('board.board_id'))
board = db.relationship("Board", back_populates="cards")

def to_json(self):
return {
"id": self.card_id,
"message": self.message,
"like_count": self.like_count,
"board_id": self.board_id,
"board": self.board.title
}

@classmethod
def create(cls, board_id, request_body):
if "message" not in request_body:
return abort(make_response({"message": "Must include message for card in request"}, 400))
return cls(message=request_body["message"], board_id=board_id, like_count=0)

# UPDATE Card
def update(self, request_body):
self.message = request_body["message"]
4 changes: 0 additions & 4 deletions app/routes.py

This file was deleted.

91 changes: 91 additions & 0 deletions app/routes/board_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from flask import Blueprint, request, jsonify, make_response
from app import db
from app.models.board import Board
from app.models.card import Card
from app.routes.helper import validate_class_instance

# example_bp = Blueprint('example_bp', __name__)
board_bp = Blueprint('board_bp', __name__, url_prefix="/boards")


# ********* BOARD *********
# CREATE new board
# CREATE BOARD - "/boards" - POST
@board_bp.route("", methods=["POST"])
def create_board():
request_body = request.get_json()
try:
new_board = Board.create(request_body)
except KeyError:
return make_response({"details": "Invalid data"}), 400

db.session.add(new_board)
db.session.commit()

return jsonify({"board": new_board.to_json()}), 201


# READ all boards
# GET ALL BOARDS - "/boards" - GET
@board_bp.route("", methods=["GET"])
def get_all_boards():
boards = Board.query.all()
boards_response = [board.to_json() for board in boards]

return jsonify(boards_response), 200


# READ one board
# GET ONE BOARDs - "/boards/1" - GET
@board_bp.route("/<id>", methods=["GET"])
def get_one_board(id):
board = validate_class_instance(id, Board)

return jsonify({"board": board.to_json()}), 200


# UPDATE cards
# UPDATE BAORD - "/boards/1" - PUT
@board_bp.route("/<id>", methods=["PUT"])
def update_board(id):
board = validate_class_instance(id, Board)
request_body = request.get_json()
board.update(request_body)

db.session.commit()

return jsonify({"board": board.to_json()}), 200


# DELETE board
# UPDATE BAORD - "/boards/1" - DELETE
@board_bp.route("/<id>", methods=["DELETE"])
def delete_board(id):
board = validate_class_instance(id, Board)

db.session.delete(board)
db.session.commit()

return jsonify({"details": f'Board {id} "{board.title}" successfully deleted'}), 200


# CREATE new card under board ID:
@board_bp.route("/<board_id>/cards", methods=["POST"])
def create_card(board_id):
request_body = request.get_json()

new_card = Card.create(board_id, request_body)

db.session.add(new_card)
db.session.commit()

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


# GET ALL cards for 1 board:
@board_bp.route("/<board_id>/cards", methods=["GET"])
def get_all_cards(board_id):
board = validate_class_instance(board_id, Board)
cards = Card.query.filter_by(board=board)

return jsonify([{"message": card.message, "like_count": card.like_count, "card_id": card.card_id, "board_id": card.board_id} for card in cards]), 200
48 changes: 48 additions & 0 deletions app/routes/card_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from flask import Blueprint, request, jsonify
from app import db
from .helper import validate_class_instance
from ..models.card import Card

# Blueprint:
card_bp = Blueprint('card_bp', __name__, url_prefix="/cards")

# GET ONE card:


# @card_bp.route("/<id>", methods=["GET"])
# def get_one_card(id):
# card = validate(id, Card)

# return jsonify({"card": card.to_json()}), 200

# UPDATE one card:
@card_bp.route("/<id>", methods=["PATCH"])
def update_card(id):
card = validate_class_instance(id, Card)
request_body = request.get_json()
card.update(request_body)

db.session.commit()

return jsonify({"card": card.to_json()}), 200


# UPDATE likes for one card:
@card_bp.route("/<id>/like", methods=["PATCH"])
def update_likes(id):
card = validate_class_instance(id, Card)
card.like_count += 1
db.session.commit()

return jsonify({"card": card.to_json()}), 200


# DELETE card:
@card_bp.route("/<id>", methods=["DELETE"])
def delete_card(id):
card = validate_class_instance(id, Card)

db.session.delete(card)
db.session.commit()

return jsonify({"details": f"Card {id} successfully deleted"}), 200
16 changes: 16 additions & 0 deletions app/routes/helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask import abort, make_response


def validate_class_instance(instance_id, cls):
try:
instance_id = int(instance_id)
except:
return abort(make_response({"message": f'{cls.__name__} {instance_id} is invalid'}, 400))

instance = cls.query.get(instance_id)

if not instance:
abort(make_response(
{"message": f'{cls.__name__} {instance_id} not found'}, 404))

return instance
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