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 - Salty Sailors - Allison Leonard, Andrea Palacios, Ekaterina Malakhova, Katrina Kimzey #21

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
065edbe
Started set up, flask init not finished
Jun 29, 2021
9b40292
Push the migrations
kmalakhova Jun 29, 2021
f803f22
Skeleton for board routes set up
Jun 29, 2021
d476183
All boards routes added
Jun 29, 2021
338907f
All board routes written but untested
Jun 29, 2021
01fac48
Board routes written and tested in Postman
Jun 29, 2021
1a14ab9
Merge pull request #1 from SterlingSunshine/K_boards_routes
kmalakhova Jun 30, 2021
069ac00
Add card routes
kmalakhova Jun 30, 2021
2983371
Minor updates
kmalakhova Jun 30, 2021
dfd6f87
Registered cards blueprint so we can test
Jun 30, 2021
415dc22
Empty commit
kmalakhova Jun 30, 2021
d6c6121
Merge branch 'main' of https://github.com/SterlingSunshine/back-end-i…
kmalakhova Jun 30, 2021
55b594a
Add edit_card() and like_card()
kmalakhova Jun 30, 2021
162fc4b
Merge pull request #2 from SterlingSunshine/card-routes
SterlingSunshine Jun 30, 2021
19589fc
Card routes work fine and pass the tests
kmalakhova Jun 30, 2021
3557e3d
Merge branch 'card-routes-completed' of https://github.com/SterlingSu…
Jun 30, 2021
45b5153
Fixed returning of cards in boards, all Postman tests now passing
Jun 30, 2021
dd6a1bc
Merge pull request #3 from SterlingSunshine/card-routes-completed
SterlingSunshine Jun 30, 2021
0366220
Merge pull request #4 from SterlingSunshine/fixed-board-routes
kmalakhova Jun 30, 2021
640b24b
Deployment ready version
Jun 30, 2021
88b8ca5
Preparing files for re-deployment
kmalakhova Jul 2, 2021
d09086d
Routes changed
kmalakhova Jul 2, 2021
79c470f
Ign
kmalakhova Jul 2, 2021
5a047d9
Update the tests
kmalakhova Jul 2, 2021
0aaa7e6
Add Postman tests
kmalakhova Jul 2, 2021
59a7347
Remove unnecessary comments
kmalakhova Jul 2, 2021
0b702a4
Rename the tests
kmalakhova Jul 2, 2021
ab3e646
Add postman requests
kmalakhova Jul 2, 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
41 changes: 28 additions & 13 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,36 @@


def create_app():
app = Flask(__name__)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
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_TESTDB_URI")

# Import models here for Alembic setup
# from app.models.ExampleModel import ExampleModel
# 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)
db.init_app(app)
migrate.init_app(app, db)

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

from .board_routes import boards_bp
app.register_blueprint(boards_bp)

from .cards_routes import cards_bp
app.register_blueprint(cards_bp)

CORS(app)
return app

80 changes: 80 additions & 0 deletions app/board_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'''
Boards Routes
- all boards => GET, POST
- single board => GET, PUT, DELETE
'''

from flask import Blueprint, request, jsonify, make_response
from app import db
from app.models.board import Board

# example_bp = Blueprint('example_bp', __name__)
boards_bp = Blueprint('board', __name__, url_prefix='/boards')

# ==============================================================
# ===== All Boards =====
# ==============================================================

@boards_bp.route("", methods=["GET"], strict_slashes=False)
def get_boards():
boards = Board.query.all()
return make_response({'boards_list' : [board.to_dict() for board in boards]}, 200)
# returns a json with a single key, the value is a list of all the boards info (id, title, owner, and list of cards)

@boards_bp.route("", methods=["POST"], strict_slashes=False)
def post_boards():
request_body = request.get_json()

try:
new_board = Board(
title=request_body["title"],
owner=request_body["owner"]
)
except KeyError:
return make_response({'details' : 'Missing data'}, 400)

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

return make_response(new_board.to_dict(), 201)
# returns all the info about the new board, including it's assigned id, no cards yet


# ==============================================================
# ===== Single Board =====
# ==============================================================

@boards_bp.route("/<board_id>", methods=["GET"], strict_slashes=False)
def get_board(board_id):
board = Board.query.get_or_404(board_id)
return make_response(board.to_dict(), 200)
# returns json with id, title, owner, cards list


@boards_bp.route("/<board_id>", methods=["PUT"], strict_slashes=False)
def put_board(board_id):
board = Board.query.get_or_404(board_id)
request_body = request.get_json()

try:
board.title=request_body["title"],
board.owner=request_body["owner"]
except KeyError:
return make_response({'details' : 'Missing data'}, 400)

db.session.commit()
return make_response(board.to_dict(), 200)
# returns json with id, title, owner, cards list

@boards_bp.route("/<board_id>", methods=["DELETE"], strict_slashes=False)
def delete_board(board_id):
board = Board.query.get_or_404(board_id)
db.session.delete(board)
db.session.commit()
return make_response({'id' : board_id}, 200)
# returns the id of the deleted board


# ==============================================================
# ===== Helper Functions =====
# ==============================================================
83 changes: 83 additions & 0 deletions app/cards_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from app import db
from app.models.card import Card
from app.models.board import Board
from flask import request, Blueprint, jsonify

cards_bp = Blueprint("cards", __name__, url_prefix="/boards")

def is_message_valid(message):
return len(message) <= 40 and len(message) > 5

def build_card_response(card):
return jsonify({"card": card.to_dict()})

def build_response(message):
return jsonify({"details": message})

def invalid_message_len_response():
return build_response("Length of the message schould be in [6,40] range")

def get_board(board_id):
board = Board.query.get(board_id)
if not board:
return None, f"Board with id {board_id} not found"
return board, None

def get_card(board_id, card_id):
board, error = get_board(board_id)
if error:
return None, error
card = Card.query.filter_by(board_id = board.board_id, card_id=card_id).first()
if not card:
return None, f"Card with id {card_id} not found"
return card, None

@cards_bp.route("<board_id>/cards/", methods = ["POST"], strict_slashes=False)
def add_card(board_id):
"""Adds a card to a board"""
board, error = get_board(board_id)
if error:
return build_response(error)
request_body = request.get_json()
message = request_body["message"]
if not is_message_valid(message):
return invalid_message_len_response()
card = Card(message = message, board_id=board_id)
db.session.add(card)
db.session.commit()
return build_card_response(card)

@cards_bp.route("<board_id>/cards/<card_id>", methods=["DELETE"], strict_slashes=False)
def delete_card(board_id, card_id):
"""Deletes a card with specified card id from a board with a specified board id"""
card, error = get_card(board_id, card_id)
if error:
return build_response(error)
card_message = card.message
db.session.delete(card)
db.session.commit()
return build_response(f"Card with id {card_id} and message '{card_message}' was successfully deleted")

@cards_bp.route("<board_id>/cards/<card_id>/like", methods=["PATCH"], strict_slashes=False)
def like_card(board_id, card_id):
"""Upvotes a card"""
card, error = get_card(board_id, card_id)
if error:
return build_response(error)
card.likes_count += 1
db.session.commit()
return build_card_response(card)

@cards_bp.route("<board_id>/cards/<card_id>/edit", methods=["PATCH"], strict_slashes=False)
def edit_card(board_id, card_id):
"""Updates message of a single card"""
card, error = get_card(board_id, card_id)
if error:
return build_response(error)
request_body = request.get_json()
message = request_body["message"]
if not is_message_valid(message):
return invalid_message_len_response()
card.message = message
db.session.commit()
return build_card_response(card)
19 changes: 19 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
'''
Board Model -
- constructor
- to_dict which formats info into a dict for response
'''
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', backref='board', lazy=True)

def to_dict(self):
return{
"id" : self.board_id,
"title" : self.title,
"owner" : self.owner,
"cards" : [card.to_dict() for card in self.cards],
}
18 changes: 18 additions & 0 deletions app/models/card.py
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
'''
Card Model -
- constructor
- to_dict which formats info into a dict for response
'''
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, default=0)
board_id = db.Column(db.Integer, db.ForeignKey('board.board_id'))

def to_dict(self):
return {
"id" : self.card_id,
"message" : self.message,
"likes" : self.likes_count,
}
4 changes: 0 additions & 4 deletions app/routes.py

This file was deleted.

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