-
Notifications
You must be signed in to change notification settings - Fork 36
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
Sea Turtles - Adriana Gutierrez, Esther Annorzie, Joanna Dudley, & Lili Parra #25
base: main
Are you sure you want to change the base?
Changes from all commits
227c09d
340954b
39b629a
d796793
57318de
c8ec7a6
43624ca
0d4fa40
712766f
909a41b
db72352
aaac7e8
f8ba08a
a13effd
a019a27
62e8195
411c710
a81af8a
692b882
73dfd45
4f2b365
a1bbbd7
8cdfa20
6fdaa86
d4ba54f
4e15002
51e5d6d
17bdb0a
24be81b
a909b89
5083264
b14421a
a8d2624
1057184
0a55ffb
8e8b731
9ab3802
e23c31a
831711d
3b5a753
c7b1660
f0ba784
9750006
f8e229b
db90d10
812b805
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
|
||
from flask import jsonify, abort, make_response | ||
import os | ||
import requests | ||
|
||
|
||
def error_message(message, status_code): | ||
abort(make_response(jsonify(dict(details=message)), status_code)) | ||
|
||
def success_message_info_as_list(message, status_code=200): | ||
return make_response(jsonify(message), status_code) | ||
|
||
def return_database_info_list(return_value): | ||
return make_response(jsonify(return_value)) | ||
|
||
def return_database_info_dict(category, return_value): | ||
return_dict = {} | ||
return_dict[category] = return_value | ||
return make_response(jsonify(return_dict)) | ||
|
||
def get_record_by_id(cls, id): | ||
try: | ||
id = int(id) | ||
except ValueError: | ||
error_message(f"Invalid id: {id}", 400) | ||
record = cls.query.get(id) | ||
if record: | ||
return record | ||
else: | ||
error_message(f"{cls.return_class_name()} id: {id} not found", 404) | ||
|
||
def create_record_safely(cls, data_dict): | ||
try: | ||
return cls.create_from_dict(data_dict) | ||
except ValueError as err: | ||
error_message(f"Invalid key(s): {err}. {cls.return_class_name()} not added to {cls.return_class_name()} List.", 400) | ||
|
||
def update_record_safely(cls, record, data_dict): | ||
try: | ||
record.update_self(data_dict) | ||
except ValueError as err: | ||
error_message(f"Invalid key(s): {err}. {cls.return_class_name()} not updated.", 400) | ||
|
||
|
||
|
||
|
||
|
||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,58 @@ | ||
from app import db | ||
|
||
class Board(db.Model): | ||
board_id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String, nullable=False) | ||
owner = db.Column(db.String, nullable=False) | ||
cards = db.relationship("Card", back_populates='board') | ||
|
||
|
||
required_attributes = { | ||
"title" : True, | ||
"owner" : True | ||
} | ||
|
||
# Instance Methods | ||
|
||
def self_to_dict(self): | ||
instance_dict = dict( | ||
board_id=self.board_id, | ||
title=self.title, | ||
owner=self.owner | ||
) | ||
|
||
card_list = [card.self_to_dict() for card in self.cards] if self.cards else [] | ||
# sort card list by card_ids to prevent cards shifting when like numbers change | ||
card_list.sort(key= lambda x: x["card_id"]) | ||
instance_dict["cards"] = card_list | ||
|
||
return instance_dict | ||
|
||
|
||
def update_self(self, data_dict): | ||
dict_key_errors = [] | ||
for key in data_dict.keys(): | ||
if hasattr(self, key): | ||
setattr(self, key, data_dict[key]) | ||
else: | ||
dict_key_errors.append(key) | ||
if dict_key_errors: | ||
raise ValueError(dict_key_errors) | ||
|
||
|
||
|
||
# Class Methods | ||
|
||
@classmethod | ||
def create_from_dict(cls, data_dict): | ||
|
||
if data_dict.keys() == cls.required_attributes.keys(): | ||
return cls(title=data_dict["title"], owner=data_dict["owner"]) | ||
else: | ||
remaining_keys= set(data_dict.keys())-set("title", "owner") | ||
response=list(remaining_keys) | ||
raise ValueError(response) | ||
Comment on lines
+49
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depending on your project, if a user sends an extra key along with the required data for an operation, you may want to still create an object with that valid info and maybe share a message that non-required keys were not be used. There's no right or wrong in this case, just something to think about when designing endpoints. |
||
|
||
@classmethod | ||
def return_class_name(cls): | ||
return cls.__name__ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,57 @@ | ||
from app import db | ||
|
||
class Card(db.Model): | ||
card_id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
message = db.Column(db.String, nullable=False) | ||
likes_count = db.Column(db.Integer, nullable=False) | ||
board_id = db.Column(db.Integer, db.ForeignKey('board.board_id'), nullable=False) | ||
board = db.relationship("Board", back_populates='cards') | ||
|
||
|
||
required_attributes = { | ||
"message" : True, | ||
"board_id" : True, | ||
} | ||
|
||
# Instance Methods | ||
def self_to_dict(self): | ||
instance_dict = dict( | ||
card_id=self.card_id, | ||
message=self.message, | ||
board_id=self.board_id, | ||
likes_count=self.likes_count | ||
) | ||
|
||
return instance_dict | ||
|
||
|
||
def update_self(self, data_dict): | ||
dict_key_errors = [] | ||
for key in data_dict.keys(): | ||
if hasattr(self, key): | ||
setattr(self, key, data_dict[key]) | ||
else: | ||
dict_key_errors.append(key) | ||
if dict_key_errors: | ||
raise ValueError(dict_key_errors) | ||
Comment on lines
+28
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could cut down on duplication of the identical |
||
|
||
|
||
# Class Methods | ||
|
||
|
||
@classmethod | ||
def create_from_dict(cls, data_dict): | ||
if data_dict.keys() == cls.required_attributes.keys(): | ||
return cls(message=data_dict["message"], | ||
board_id = data_dict["board_id"], | ||
likes_count = 0 | ||
) | ||
|
||
else: | ||
remaining_keys= set(data_dict.keys())-set(cls.required_attributes.keys()) | ||
response=list(remaining_keys) | ||
raise ValueError(response) | ||
|
||
@classmethod | ||
def return_class_name(cls): | ||
return cls.__name__ |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from flask import Blueprint, request, jsonify, make_response | ||
from app import db | ||
from app.models.board import Board | ||
from app.helper_functions import success_message_info_as_list, get_record_by_id, return_database_info_dict, error_message, create_record_safely | ||
from app.models.card import Card | ||
|
||
board_bp = Blueprint('Boards', __name__, url_prefix='/boards') | ||
|
||
# create one board | ||
@board_bp.route("", methods=["POST"]) | ||
def create_new_board(): | ||
request_body = request.get_json() | ||
new_board = create_record_safely(Board, request_body) | ||
|
||
db.session.add(new_board) | ||
db.session.commit() | ||
|
||
return success_message_info_as_list(dict(board=new_board.self_to_dict()), 201) | ||
|
||
# read all boards | ||
@board_bp.route("", methods=["GET"]) | ||
def get_boards(): | ||
boards = Board.query.all() | ||
boards_response = [board.self_to_dict() for board in boards] | ||
return success_message_info_as_list(boards_response, status_code=200) | ||
|
||
# reading one board | ||
@board_bp.route("/<board_id>", methods=["GET"]) | ||
def get_one_board(board_id): | ||
board = get_record_by_id(Board, board_id) | ||
return return_database_info_dict("board", board.self_to_dict()) | ||
|
||
# read all cards by board id | ||
@board_bp.route("/<board_id>/cards", methods=["GET"]) | ||
def get_cards_by_board_id(board_id): | ||
board = get_record_by_id(Board, board_id) | ||
|
||
return success_message_info_as_list(board.self_to_dict()) | ||
|
||
# creating one card | ||
@board_bp.route("/<board_id>/cards", methods=["POST"]) | ||
def create_card(board_id): | ||
request_body = request.get_json() | ||
if "message" not in request_body: | ||
error_message("Message not found", 400) | ||
|
||
request_body["board_id"] = board_id | ||
card = Card.create_from_dict(request_body) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we also use the helper |
||
board = get_record_by_id(Board, board_id) | ||
|
||
db.session.add(card) | ||
db.session.commit() | ||
|
||
return success_message_info_as_list(dict(board=board.self_to_dict()), 201) | ||
|
||
# Delete one board | ||
@board_bp.route("/<board_id>", methods=["DELETE"]) | ||
def delete_one_board(board_id): | ||
board = get_record_by_id(Board, board_id) | ||
|
||
for card in board.cards: | ||
db.session.delete(card) | ||
|
||
db.session.delete(board) | ||
db.session.commit() | ||
|
||
return success_message_info_as_list(dict(details=f'Board {board.board_id} "{board.title}" successfully deleted')) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from flask import Blueprint, request, jsonify, make_response | ||
from app import db | ||
from app.models.card import Card | ||
from app.helper_functions import * | ||
|
||
card_bp = Blueprint('Cards', __name__, url_prefix='/cards') | ||
|
||
|
||
@card_bp.route("/<card_id>", methods=["PATCH"]) | ||
def update_card(card_id): | ||
card = get_record_by_id(Card, card_id) | ||
|
||
request_body = request.get_json() | ||
|
||
update_record_safely(Card, card, request_body) | ||
|
||
db.session.commit() | ||
|
||
return return_database_info_dict("card", card.self_to_dict()) | ||
|
||
#deleting one card | ||
@card_bp.route("/<card_id>", methods=["DELETE"]) | ||
def delete_one_card(card_id): | ||
card = get_record_by_id(Card, card_id) | ||
db.session.delete(card) | ||
db.session.commit() | ||
|
||
return success_message_info_as_list(dict(details=f'Card {card.card_id} \"{card.message}\" successfully deleted')) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Generic single-database configuration. |
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love all the helper functions!