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

Tigers - Masha, Neema, Thao, and Yael #22

Open
wants to merge 78 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
fb4f978
back-end set up initial set up
thaocodes Jan 2, 2023
27f93db
add models and blueprints
n2020h Jan 3, 2023
478df78
commit blueprints
n2020h Jan 3, 2023
ddeffee
boards_bp in board_routes
mariia-iureva Jan 3, 2023
757d89e
Adds model import to head of board_routes
yaelso Jan 3, 2023
ff642b5
Added validate_model, GET 1 board by id, to-dict in Board model
mariia-iureva Jan 3, 2023
5618a76
Modifies create_app to handle test mode
yaelso Jan 4, 2023
3757913
add delete_card and get_all_boards
n2020h Jan 4, 2023
f266c06
"removed unnecessary lines"
n2020h Jan 4, 2023
dee69d2
Creates testing fixtures for one and three boards
yaelso Jan 4, 2023
e302876
Creates initial card_routes tests
yaelso Jan 4, 2023
da327d3
Creates initial board_routes tests
yaelso Jan 4, 2023
2c97378
made POST endoint for 1 board
thaocodes Jan 4, 2023
017f7b4
created class method from_dict
thaocodes Jan 4, 2023
159e29c
Merge branch 'thao' of https://github.com/mariia-iureva/back-end-insp…
n2020h Jan 4, 2023
b6ee6d6
Merge pull request #1 from mariia-iureva/Masha01
n2020h Jan 4, 2023
5f04688
Adds missing fixture decorator
yaelso Jan 4, 2023
73be5bd
fixed error in error code
thaocodes Jan 4, 2023
ef3b014
get all boards
n2020h Jan 4, 2023
26b7a78
Merge branch 'main' into Yael
yaelso Jan 4, 2023
624c2c1
merge conflicts resolved
thaocodes Jan 4, 2023
a6dc50c
"removed junk"
n2020h Jan 4, 2023
578df2f
Merge branch 'main' into thao
thao325 Jan 4, 2023
9a2fee9
Merge pull request #2 from mariia-iureva/thao
thao325 Jan 4, 2023
91e62f2
Merge branch 'main' into Yael
yaelso Jan 4, 2023
03643c0
"resolve merges"
n2020h Jan 4, 2023
c0a9524
Merge branch 'main' into Neema
n2020h Jan 4, 2023
ea3385b
Merge pull request #3 from mariia-iureva/Neema
n2020h Jan 4, 2023
9acf982
Merge branch 'main' into Yael
yaelso Jan 4, 2023
1bdebe4
more merge conflicts hopefully fixed
thaocodes Jan 4, 2023
67f20e7
fixed small typo
thaocodes Jan 4, 2023
b014c8f
Merge branch 'main' into Yael
yaelso Jan 4, 2023
38cde0d
add owner
mariia-iureva Jan 4, 2023
fd0b38f
Merge pull request #4 from mariia-iureva/Yael
yaelso Jan 4, 2023
95f47ec
Merge branch 'main' into Masha01
mariia-iureva Jan 4, 2023
8681cb6
added like (update) one card endpoint
thaocodes Jan 5, 2023
288c007
test for POST 1 board done
thaocodes Jan 5, 2023
a174fb3
Added 3 tests for GET board by id
mariia-iureva Jan 5, 2023
e27d6f6
completed tests for POST 1 board with missing title/owner
thaocodes Jan 5, 2023
ff47dbb
Implements one to many relationship between Board and Card
yaelso Jan 5, 2023
674da48
Implements one to many relationship with Card in Board model
yaelso Jan 5, 2023
01664ea
Adds card check to to_dict func
yaelso Jan 5, 2023
d671d9d
Applies migrations to link card and board models
yaelso Jan 5, 2023
f3fa5a3
Implemenets to_dict and from_dict methods in Card model
yaelso Jan 6, 2023
e07bfd8
Implements logic to create one card for board by board ID
yaelso Jan 6, 2023
31c2433
Implements logic to get all cards for board by board ID
yaelso Jan 6, 2023
562c128
Implements update helper function to be called on like_count modifica…
yaelso Jan 6, 2023
6cc2cd8
Implements tests for POST card
yaelso Jan 6, 2023
c147a20
Adding GET all cards in card_routes for testing purposes
mariia-iureva Jan 6, 2023
c474185
Merge pull request #5 from mariia-iureva/Masha01
n2020h Jan 6, 2023
cba6f43
Merge branch 'main' into Yael
yaelso Jan 6, 2023
ca91988
working on update card likes test
thaocodes Jan 6, 2023
0541650
Merge branch 'main' into thao
thaocodes Jan 6, 2023
032b440
Uncomments lines from Neema's DELETE route
yaelso Jan 6, 2023
b223f6a
Merge pull request #6 from mariia-iureva/Yael
n2020h Jan 6, 2023
d3d3dc4
working on PUT test
thaocodes Jan 6, 2023
88a61e4
merge conflicts resolved
thaocodes Jan 6, 2023
9354d25
fixed board to_dict
thaocodes Jan 6, 2023
42960fe
update one card fixes
thaocodes Jan 6, 2023
fa3d77d
test database set up
thaocodes Jan 6, 2023
595702d
Modifies POST board 400 response and implements more CRUD tests for b…
yaelso Jan 17, 2023
1b23935
Modifies GET all cards in card_routes to utilize to_dict method
yaelso Jan 17, 2023
d57e200
Creates testing fixture for one card to one board relationship
yaelso Jan 17, 2023
8083280
Implements more board route CRUD tests
yaelso Jan 17, 2023
7369124
Modifies GET cards for board to make use of board to_dict method
yaelso Jan 17, 2023
e42889d
Implements tests for GET cards for board
yaelso Jan 17, 2023
e4d6e90
Implements tests for DELETE one card
yaelso Jan 17, 2023
b7e4b33
Modifies Card model to take default likes_count of 0
yaelso Jan 17, 2023
9214d78
Removes create_one_board test to make way for Thao's
yaelso Jan 17, 2023
cf79cab
Adds test cases for delete card
yaelso Jan 17, 2023
671f0a1
changed put to patch endpoint, changed test
thaocodes Jan 17, 2023
91886ee
Merge pull request #7 from mariia-iureva/thao
mariia-iureva Jan 17, 2023
5915628
Resolves merge conflicts
yaelso Jan 17, 2023
e42a350
Merge pull request #8 from mariia-iureva/Yael
n2020h Jan 17, 2023
44222e2
Sorting behavior
mariia-iureva Jan 18, 2023
733c273
Merge branch 'main' into Masha01
yaelso Jan 18, 2023
ab6307c
Merge pull request #9 from mariia-iureva/Masha01
mariia-iureva Jan 18, 2023
8804f2e
updated likesendpoint
mariia-iureva Jan 20, 2023
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
23 changes: 16 additions & 7 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,31 @@
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 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")

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

from app.card_routes import cards_bp
app.register_blueprint(cards_bp)

CORS(app)
return app
106 changes: 106 additions & 0 deletions app/board_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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.validate_data import validate_model

boards_bp = Blueprint("boards", __name__, url_prefix="/boards")


#======================================
# CREATE ONE BOARD
#======================================

@boards_bp.route("", methods=["POST"])
def create_board():
request_body = request.get_json()
if "title" not in request_body or \
"owner" not in request_body:
return make_response({"details":"Invalid request; missing necessary field(s)"}, 400)

new_board = Board.from_dict(request_body)

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

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



#======================================
# GET ALL BOARDS
#======================================


@boards_bp.route("", methods=["GET"])
def read_all_boards():

boards = Board.query.all()

boards_response = [] # returns empty list if no goals

for board in boards:
boards_response.append({
"board_id": board.board_id,
"title": board.title,
"owner": board.owner,
})

return jsonify(boards_response), 200


# ===================================
# READ ONE BOARD BY ID
# ===================================

@boards_bp.route("/<board_id>", methods=["GET"])
def read_one_board(board_id):
board = validate_model(Board, board_id)
response_one_board = {"board": Board.to_dict(board)}
return jsonify(response_one_board), 200


#======================================
# CREATE ONE CARD
#======================================

@boards_bp.route("/<board_id>/cards", methods=["POST"])
def create_card(board_id):
validate_board = validate_model(Board, board_id)
board = Board.query.get(validate_board.board_id)

request_body = request.get_json()

if not "message" in request_body:
return make_response({"details":"Invalid request; message field missing"}, 400)
elif len(request_body["message"]) < 1:
return make_response({"details":"Invalid request; message field cannot be empty"}, 400)
elif len(request_body["message"]) > 40:
return make_response({"details":"Invalid request; message over 40 characters"}, 400)

new_card = Card.from_dict(request_body, board)

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

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


#======================================
# GET ALL CARDS FOR BOARD
#======================================

@boards_bp.route("/<board_id>/cards", methods=["GET"])
def get_cards_for_board(board_id):
board = validate_model(Board, board_id)
board_dict = board.to_dict(cards=True)
sort_param = request.args.get("sort")

if sort_param == "id":
board_dict["cards"].sort(key=lambda c: c.get("id"))
elif sort_param == "alphabet":
board_dict["cards"].sort(key=lambda c: c.get("message"))
elif sort_param == "likes":
board_dict["cards"].sort(key=lambda c: c.get("likes_count"), reverse=True) #descending order starting from lagest number of likes

return board_dict
50 changes: 50 additions & 0 deletions app/card_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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.validate_data import validate_model

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



#======================================
# GET ALL CARDS
#======================================


@cards_bp.route("", methods=["GET"])
def read_all_cards():

cards = Card.query.all()

return jsonify([card.to_dict() for card in cards])

# ===================================
# DELETE ONE CARD BY ID
# ===================================


@cards_bp.route("/<card_id>", methods=["DELETE"])
def delete_card(card_id):
card = validate_model(Card, card_id)

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

delete_message = f'Card {card_id} successfully deleted'
return delete_message, 200

# ===================================
# LIKE (UPDATE) ONE CARD
# ===================================
@cards_bp.route("/<card_id>/like", methods=["PATCH"])
def like_card(card_id):
card = validate_model(Card, card_id)
card.likes_count += 1

db.session.commit()

# return make_response("card liked", 200)
return {"likes_count": card.likes_count}, 200

30 changes: 30 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
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)

@classmethod
def from_dict(cls, req_body):
return cls(
title=req_body["title"],
owner=req_body["owner"]
)



def to_dict(self, cards=False):
board = {
"id": self.board_id,
"title": self.title,
"owner": self.owner
}

if cards:
board["cards"] = [card.to_dict() for card in self.cards]

return board


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

def to_dict(self):
card = {
"id": self.card_id,
"message": self.message,
"likes_count": self.likes_count,
"board_id": self.board_id
}

return card

def update(self, card_data):
self.likes_count = card_data["likes_count"]

@classmethod
def from_dict(cls, card_data, board):
return cls(message=card_data["message"], board_id=board.board_id)
4 changes: 0 additions & 4 deletions app/routes.py

This file was deleted.

15 changes: 15 additions & 0 deletions app/validate_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from app import db
from flask import abort, make_response, jsonify

def validate_model(class_obj, object_id):
try:
object_id = int(object_id)
except:
abort(make_response(jsonify({"message": f"{class_obj.__name__} {object_id} has an invalid id"}), 400))

query_result = class_obj.query.get(object_id)

if not query_result:
abort(make_response({"message": f"{class_obj.__name__} {object_id} not found"}, 404))

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