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

Snow leopards - Alaere N., Anika SW., Hoku M., Mia Y. #14

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
88bb775
Created new branch, models, tests, and routes for boards
Alaere00 Jan 3, 2023
dcfdd21
Completed routes for get methods, methods working postman
Alaere00 Jan 4, 2023
b64eac6
Add one-to-many relationship and card_routes
MiaCY Jan 4, 2023
88f9f06
Created routes for delete, added more test
Alaere00 Jan 5, 2023
f3862b8
Slack message complete moving onto to final board routes
Alaere00 Jan 5, 2023
c4f2222
Slack message complete moving onto to final board routes
Alaere00 Jan 5, 2023
e414ccb
Removed extra function
Alaere00 Jan 5, 2023
3f981f6
Merge branch 'test-and-board-routes' of https://github.com/Alaere00/b…
Alaere00 Jan 5, 2023
3945c49
Merge branch 'card-routes' of https://github.com/Alaere00/back-end-in…
Alaere00 Jan 6, 2023
c6f78ee
Completed one to many route for boards & cards
Alaere00 Jan 6, 2023
e0166df
Add PATCH endpoint
MiaCY Jan 6, 2023
05f928b
typo
MiaCY Jan 6, 2023
f502c27
Merge branch 'card-routes' of https://github.com/Alaere00/back-end-in…
Alaere00 Jan 6, 2023
3fc99dd
Add new board table
hokumcangus Jan 6, 2023
d286df0
Created more routes, completed tests
Alaere00 Jan 16, 2023
4b19555
Quick fix on function names
Alaere00 Jan 16, 2023
419d458
refactor
MiaCY Jan 17, 2023
019bd40
Fix migrations
hokumcangus Jan 17, 2023
bb9349f
refactor card_bp
MiaCY Jan 17, 2023
b4f8bc5
Merge branch 'main' of https://github.com/Alaere00/back-end-inspirati…
MiaCY Jan 17, 2023
084e61a
fixed routes for update likes & delete card by id
Alaere00 Jan 19, 2023
599498c
testing
Alaere00 Jan 19, 2023
1de5c86
testing
Alaere00 Jan 19, 2023
c2919aa
Fixing route
Alaere00 Jan 19, 2023
0958f56
Merge branch 'main' of https://github.com/Alaere00/back-end-inspirati…
Alaere00 Jan 19, 2023
de98c43
small fix in routes
Alaere00 Jan 19, 2023
53c09ab
checked error
Alaere00 Jan 19, 2023
c2a6b9c
still testing
Alaere00 Jan 19, 2023
8d12777
Final commit, routes work all tests pass
Alaere00 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
17 changes: 12 additions & 5 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,29 @@
load_dotenv()


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

app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get(
"SQLALCHEMY_DATABASE_URI")
if not config:
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 import board_bp
from .card_routes import card_bp
app.register_blueprint(board_bp)
app.register_blueprint(card_bp)

CORS(app)
return app
60 changes: 60 additions & 0 deletions app/card_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from flask import Blueprint, request, jsonify, make_response, abort
from flask_sqlalchemy import SQLAlchemy
from app import db
from app.models.board import Board
from app.models.card import Card
from app.routes import validate_model

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

@card_bp.route("", methods=["POST"])
def create_new_card():
request_body = request.get_json()

if "likes" not in request_body or "message" not in request_body:
return make_response(jsonify({"details":"Invalid data"}), 400)

new_card = Card.from_dict(request_body)

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

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

@card_bp.route("", methods=["GET"])
def get_all_cards():
cards_response = []
cards = Card.query.all()

cards_response = [card.to_dict() for card in cards]
# print(cards_response)

return jsonify(cards_response), 200

@card_bp.route("", methods=["DELETE"])
def delet_all_cards():
cards = Card.query.all()

for card in cards:
db.session.delete(card)
db.session.commit()

return make_response({"details": "Cards successfully deleted"}), 200

@card_bp.route("/<card_id>", methods=["GET"])
def get_one_card(card_id):
card = validate_model(Card, card_id)
return make_response(jsonify({"card":card.to_dict()}), 200)

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

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

return make_response({"details": f"Card {card_id} \"{card.message}\" successfully deleted"}), 200




23 changes: 23 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
from app import db

class Board(db.Model):
board_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
owner = db.Column(db.String)
title = db.Column(db.String)
cards = db.relationship("Card", back_populates="board")


def to_dict(self):
board_dict = {
"board_id" : self.board_id,
"owner": self.owner,
"title": self.title,
}
if self.cards:
board_dict["cards"] = [card.to_dict() for card in self.cards]

return board_dict

@classmethod
def create_board(cls, board_data):
return cls(owner=board_data["owner"], title=board_data["title"])

20 changes: 20 additions & 0 deletions app/models/card.py
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
from app import db

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

def to_dict(self):
card_dict = {
"card_id" : self.card_id,
"likes": self.likes,
"message": self.message,
}

return card_dict

@classmethod
def from_dict(cls, card_data):
return Card(likes=card_data["likes"],message=card_data["message"])
160 changes: 158 additions & 2 deletions app/routes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,160 @@
from flask import Blueprint, request, jsonify, make_response
from flask import Blueprint, request, jsonify, make_response, abort
from app import db
import os
import requests
from app.models.board import Board
from app.models.card import Card

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


def validate_model(cls, model_id):
try:
model_id = int(model_id)
except:
if model_id:
abort(make_response({"message": f"{cls.__name__} {model_id} invalid"}, 400))

model = cls.query.get(model_id)

if not model:
abort(make_response({"message":f"{cls.__name__} {model_id} does not exist"}, 404))

return model

@board_bp.route("", methods=["GET"])
def get_all_boards():

boards = Board.query.all()
all_boards = [board.to_dict() for board in boards]

return jsonify(all_boards)

@board_bp.route("/<board_id>", methods=["GET"])
def get_board_by_id(board_id):

board = validate_model(Board, board_id)

return make_response({"boards": board.to_dict()})

def post_to_slack(message):
url = "https://slack.com/api/chat.postMessage"

data = {
"channel": "C04FZS8P2BH",
"text": message
}
header_key = os.environ.get("authorization")

response = requests.post(url=url, json=data,
headers={"Authorization": header_key})

return response

@board_bp.route("", methods=["POST"])
def create_board():
request_body = request.get_json()

if not "owner" in request_body or not "title" in request_body:
abort(make_response({"details": "Invalid data"}, 400))

new_board = Board.create_board(request_body)

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

# post_to_slack(f"New board {new_board.title} has been created")

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


@board_bp.route("", methods=["DELETE"])
def delete_all_boards():

boards = Board.query.all()
for board in boards:
db.session.delete(board)
db.session.commit()

return make_response({"details": f"Boards successfully deleted"}, 200)


@board_bp.route("/<board_id>", methods=["DELETE"])
def delete_board_by_id(board_id):

board = validate_model(Board, board_id)

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

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

@board_bp.route("/<board_id>/cards", methods=["POST"])
def post_cards_under_board(board_id):

board = validate_model(Board, board_id)
request_body = request.get_json()
card_details = request_body["message"]

card = Card(board_id=board.board_id, likes=0, message=card_details)

db.session.add(card)
db.session.commit()

return make_response({"board_id": board.board_id, "cards": card.to_dict()}, 201)

@board_bp.route("/<board_id>/cards", methods=["GET"])
def get_card_under_board(board_id):

board = validate_model(Board, board_id)
cards = Card.query.filter_by(board_id=board.board_id).all()
card_list = [card.to_dict() for card in cards]

return make_response({"board_id": board.board_id, "cards": card_list}, 200)

@board_bp.route("/<board_id>/cards", methods=["DELETE"])
def delete_all_cards_from_board(board_id):
board = validate_model(Board, board_id)
cards = Card.query.filter_by(board_id=board.board_id).all()


if not cards:
return make_response("No cards found", 404)
else:
for card in cards:
db.session.delete(card)
db.session.commit()

return make_response(f"All cards from board {board_id} have been deleted", 200)


@board_bp.route("/<board_id>/cards/<card_id>", methods=["DELETE"])
def delete_card(board_id, card_id):
board = validate_model(Board, board_id)
if board is None:
return make_response(jsonify({"error": "Board not found"}), 404)

card = validate_model(Card, card_id)
if card not in board.cards:
return make_response(jsonify({"error": "Card not found in this board"}), 404)

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

return make_response(jsonify({"details": f"Card {card_id} \"{card.message}\" successfully deleted"}), 200)


@board_bp.route("/<board_id>/cards/<card_id>", methods=["PATCH"])
def update_likes_in_card(board_id, card_id):
card = validate_model(Card, card_id)

if card is None:
return make_response(jsonify({"error": "Card not found"}), 400)

card.likes += 1

db.session.commit()

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


# example_bp = Blueprint('example_bp', __name__)
1 change: 1 addition & 0 deletions migrations/README
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Single-database configuration for Flask.
50 changes: 50 additions & 0 deletions migrations/alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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,flask_migrate

[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

[logger_flask_migrate]
level = INFO
handlers =
qualname = flask_migrate

[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