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

Inspiration Board Backend #21

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c0cff7a
mm:setup backend project
mitramagh Jun 27, 2022
da48e19
mm:Board and Card Model and migration folder added
mitramagh Jun 27, 2022
e084d6a
kat: delete unrelated import statement turtle from model board.py
kkatottn Jun 27, 2022
2a328d2
mm:migration folder recreated
mitramagh Jun 28, 2022
65ebc4f
JL: imported board model to routes, made board blueprint, registered…
Jenny-PL Jun 28, 2022
b388e85
JL: started board POST request and validate helper board_id helper fu…
Jenny-PL Jun 28, 2022
bdd818a
kat: Add CRUD endpoints for Card model, Add instance method that retu…
kkatottn Jun 28, 2022
f242010
made route folder and card and board route files
Jenny-PL Jun 28, 2022
f5c14c0
not all changes were reflected on github
Jenny-PL Jun 29, 2022
9fab916
added routes for GET and POST for boards
mitramagh Jun 29, 2022
5281576
mm:updated model and added nullable to board_id
mitramagh Jun 29, 2022
9f2c672
mm:trying to post a card for a specific id
mitramagh Jun 29, 2022
8a55f87
deleted extra comments
Jenny-PL Jun 29, 2022
b865a46
updated response to be more detailed for create_one_card
Jenny-PL Jun 29, 2022
6992e60
JL: added comments to-do for PUT route
Jenny-PL Jun 29, 2022
113efda
MM and JL: modified PUT HTTP method to increase like_count. Modified …
Jenny-PL Jun 29, 2022
1aa4152
kat: fix bug in return statement
kkatottn Jul 1, 2022
abb8d75
updated Put route for updating likes M+Y+J+K
mitramagh Jul 19, 2022
3889f8c
added Delete Board route M+Y+J+K
mitramagh Jul 19, 2022
fc1b88d
Deleted extra Card POST route M+Y+K+J
mitramagh Jul 19, 2022
56dd3a2
add code to send msg to slack for new card creation
kkatottn Jul 19, 2022
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
7 changes: 7 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@ def create_app():

# Import models here for Alembic setup
# from app.models.ExampleModel import ExampleModel
from .models.board import Board
from .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 cards_bp
app.register_blueprint(cards_bp)

CORS(app)
return app
7 changes: 7 additions & 0 deletions app/models/board.py
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
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)
16 changes: 16 additions & 0 deletions app/models/card.py
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
from app import db


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, default=0)
board_id = db.Column(db.Integer, db.ForeignKey(
'board.board_id'), nullable=True)
board = db.relationship("Board", back_populates="cards")

def get_dict(self):
return {
'card_id': self.card_id,
'message': self.message,
'like_count': self.like_count
}
4 changes: 0 additions & 4 deletions app/routes.py

This file was deleted.

152 changes: 152 additions & 0 deletions app/routes/board_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from flask import Blueprint, request, jsonify, make_response
from flask import abort
from app import db
from os import abort
import os
import requests

from app.models.board import Board
from app.models.card import Card

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

# 1. POST - Create a new board, by filling out a form. The form includes "title" and "owner" name of the board.
# POST displays ERROR msg if empty/blank/invalid/missing "title" or "owner" input.


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

new_board = Board(
title=request_body['title'], owner=request_body['owner'])

db.session.add(new_board)
db.session.commit()
return {
'id': new_board.board_id,
'title': new_board.title,
'msg': f'{new_board.owner} created {new_board.title}'
}, 201

# helper function:


def validate_board_input(request_body):
if "title" not in request_body or "title" == "":
abort(make_response(
{"details": "Invalid data. Title missing or invalid from board"}, 400))
if "owner" not in request_body or "owner" == "":
abort(make_response(
{"details": "Invalid data. Owner missing or invalid from board"}, 400))
return request_body

# GET- Read; View a list of all boards


@board_bp.route("", methods=["GET"])
def get_all_boards():
boards = Board.query.all()
boards_response = []
for board in boards:
boards_response.append({
"id": board.board_id,
"owner": board.owner,
"title": board.title,
# not returning card list at this time. May want to add in later.
})

return jsonify(boards_response), 200
# GET - Read; Select a specific board


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

response = {
"id": chosen_board.board_id,
"owner": chosen_board.owner,
"title": chosen_board.title,
# not returning card list at this time. May want to add in later.
}
return jsonify(response), 200


# GET- Read all cards in a selected board
@board_bp.route("/<board_id>/cards", methods=["GET"])
def get_all_cards_for_board(board_id):
chosen_board = validate_board(board_id)
chosen_board_cards = []
for card in chosen_board.cards:
chosen_board_cards.append({
'card_id': card.card_id,
'message': card.message,
'like_count': card.like_count,
'board_id': card.board_id
})
return jsonify(chosen_board_cards), 200


# Helper function to validate board_id:

def validate_board(board_id):
try:
board_id = int(board_id)
except:
abort(make_response(
{"message": f"Board: {board_id} is not a valid board id"}, 400))
board = Board.query.get(board_id)
if not board:
abort(make_response(
{"message": f"Board: #{board_id} not found"}, 404))
return board

# POST: Create a new card for the selected board,
# by filling out a form and filling out a "message."
# See an error message if I try to make the card's "message" more than 40 characters.
# All error messages can look like a new section on the screen, a red outline around the input field, and/or disabling the input, as long as it's visible
# See an error message if I try to make a new card with an empty/blank/invalid/missing "message."


@board_bp.route("/<board_id>/card", methods=["POST"])
def create_card_for_board(board_id):
board = validate_board(board_id)
request_body = request.get_json()

if len(request_body["message"]) > 0 and len(request_body["message"]) <= 40:
new_card = Card(
message=request_body["message"],
board=board,
)
else:
abort(make_response(
{"message": f"Card message for board #{board_id} too long, please keep it under 40 characters"}, 400))

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

SLACK_URL = 'https://slack.com/api/chat.postMessage'
msg_to_post = {"text": f"Someone just created the card {new_card.message}", "channel" : "C03M57Y7JDC"}
auth = os.environ.get('SLACK_BOT_TOKEN')
requests.post(SLACK_URL, json=msg_to_post, headers={'Authorization': f'Bearer {auth}'})

return {
'msg': f'Succesfully created new card for {board.title}',
'message': new_card.message,
'card_id': new_card.card_id,
'like_count': new_card.like_count,
'board_id': board_id
}, 201


@board_bp.route('/<board_id>', methods=['DELETE'])
def delete_one_board(board_id):
board = validate_board(board_id)

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

rsp = {'msg': f'Board #{board.board_id} successfully deleted!'}
return jsonify(rsp), 200
77 changes: 77 additions & 0 deletions app/routes/card_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from flask import Blueprint, request, jsonify, make_response
from flask import abort
from app import db
from os import abort

from app.models.card import Card


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


# @cards_bp.route('', methods=['GET'])
# def get_all_cards():
# cards = Card.query.all()
# cards_response = []
# for card in cards:
# cards_response.append({
# 'message': card.message,
# 'card_id': card.card_id,
# 'like_count': card.like_count
# })
# return jsonify(cards_response), 200


# @cards_bp.route('/<card_id>', methods=['GET'])
# def get_one_card(card_id):
# card = validate_card(card_id)
# return jsonify({
# 'message': card.message,
# 'card_id': card.card_id,
# 'like_count': card.like_count
# }), 200


@cards_bp.route('/<card_id>', methods=['PUT'])
def update_one_card(card_id):
card = validate_card(card_id)
try:
card.like_count += 1
except KeyError:
return {
'msg': 'Update failed. like_count is required!'
}, 400

db.session.commit()
return jsonify({
'message': card.message,
'card_id': card.card_id,
'like_count': card.like_count
}), 200


@cards_bp.route('/<card_id>', methods=['DELETE'])
def delete_one_card(card_id):
card = validate_card(card_id)

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

rsp = {'msg': f'Card #{card.card_id} successfully deleted!'}
return jsonify(rsp), 200


def validate_card(card_id):
try:
card_id = int(card_id)
except:
rsp = {"msg": f"Card with id {card_id} is invalid."}
abort(make_response(rsp, 400))

card = Card.query.get(card_id)

if not card:
rsp = {'msg': f'Could not find card with id {card_id}.'}
abort(make_response(rsp, 404))

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