From e0466ab1380ff5cba70664d1afb4985fab379ec1 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Mon, 27 Jun 2022 15:57:01 -0700 Subject: [PATCH 01/10] Created Board and Card modelsand migration folder --- app/__init__.py | 3 + app/models/board.py | 6 ++ app/models/card.py | 7 ++ migrations/README | 1 + migrations/alembic.ini | 45 +++++++++ migrations/env.py | 96 +++++++++++++++++++ migrations/script.py.mako | 24 +++++ ...2fb4428_added_foreign_key_to_card_model.py | 30 ++++++ migrations/versions/90d860cbf78d_.py | 33 +++++++ .../d01573c720c0_created_card_model.py | 33 +++++++ 10 files changed, 278 insertions(+) create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/577622fb4428_added_foreign_key_to_card_model.py create mode 100644 migrations/versions/90d860cbf78d_.py create mode 100644 migrations/versions/d01573c720c0_created_card_model.py diff --git a/app/__init__.py b/app/__init__.py index 1c821436..80b98536 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -20,6 +20,9 @@ def create_app(): # 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) diff --git a/app/models/board.py b/app/models/board.py index 147eb748..fb9d40cd 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -1 +1,7 @@ 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", lazy = True) diff --git a/app/models/card.py b/app/models/card.py index 147eb748..a6632eeb 100644 --- a/app/models/card.py +++ b/app/models/card.py @@ -1 +1,8 @@ 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=True) + board = db.relationship("Board", back_populates="cards") \ No newline at end of file diff --git a/migrations/README b/migrations/README new file mode 100644 index 00000000..98e4f9c4 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 00000000..f8ed4801 --- /dev/null +++ b/migrations/alembic.ini @@ -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 diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 00000000..8b3fb335 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 00000000..2c015630 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/577622fb4428_added_foreign_key_to_card_model.py b/migrations/versions/577622fb4428_added_foreign_key_to_card_model.py new file mode 100644 index 00000000..e0c1db93 --- /dev/null +++ b/migrations/versions/577622fb4428_added_foreign_key_to_card_model.py @@ -0,0 +1,30 @@ +"""Added foreign key to Card model + +Revision ID: 577622fb4428 +Revises: d01573c720c0 +Create Date: 2022-06-27 15:54:32.755068 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '577622fb4428' +down_revision = 'd01573c720c0' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('card', sa.Column('board_id', sa.Integer(), nullable=True)) + op.create_foreign_key(None, 'card', 'board', ['board_id'], ['board_id']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'card', type_='foreignkey') + op.drop_column('card', 'board_id') + # ### end Alembic commands ### diff --git a/migrations/versions/90d860cbf78d_.py b/migrations/versions/90d860cbf78d_.py new file mode 100644 index 00000000..9088fe95 --- /dev/null +++ b/migrations/versions/90d860cbf78d_.py @@ -0,0 +1,33 @@ +"""empty message + +Revision ID: 90d860cbf78d +Revises: +Create Date: 2022-06-27 15:49:27.832755 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '90d860cbf78d' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('board', + sa.Column('board_id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('title', sa.String(), nullable=False), + sa.Column('owner', sa.String(), nullable=False), + sa.PrimaryKeyConstraint('board_id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('board') + # ### end Alembic commands ### diff --git a/migrations/versions/d01573c720c0_created_card_model.py b/migrations/versions/d01573c720c0_created_card_model.py new file mode 100644 index 00000000..e2032bdd --- /dev/null +++ b/migrations/versions/d01573c720c0_created_card_model.py @@ -0,0 +1,33 @@ +"""Created Card model + +Revision ID: d01573c720c0 +Revises: 90d860cbf78d +Create Date: 2022-06-27 15:51:23.424419 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd01573c720c0' +down_revision = '90d860cbf78d' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('card', + sa.Column('card_id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('message', sa.String(), nullable=False), + sa.Column('likes_count', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('card_id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('card') + # ### end Alembic commands ### From 8b637ca492c26e63ac5e21af402fe81d50a7e4c7 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Tue, 28 Jun 2022 12:27:35 -0700 Subject: [PATCH 02/10] Created blueprint boards_bp, added HTTP routes for GET, POST --- app/__init__.py | 6 ++++++ app/models/board.py | 20 ++++++++++++++++++++ app/routes.py | 4 ---- app/routes/__init__.py | 0 app/routes/board_routes.py | 29 +++++++++++++++++++++++++++++ app/routes/card_routes.py | 0 6 files changed, 55 insertions(+), 4 deletions(-) delete mode 100644 app/routes.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/board_routes.py create mode 100644 app/routes/card_routes.py diff --git a/app/__init__.py b/app/__init__.py index 80b98536..eee31feb 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,6 +29,12 @@ def create_app(): # Register Blueprints here # from .routes import example_bp # app.register_blueprint(example_bp) + from app.routes.board_routes import boards_bp + app.register_blueprint(boards_bp) + + #use later + # from app.routes.card_routes import cards_bp + # app.register_blueprint(cards_bp) CORS(app) return app diff --git a/app/models/board.py b/app/models/board.py index fb9d40cd..6227324a 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -1,7 +1,27 @@ from app import db +from flask import make_response, abort +# from .card import Task +# from app.routes.helpers import validate_model_instance 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", lazy = True) + + def to_json(self): + return {"boardId" : self.board_id, + "title" : self.title, + "owner": self.owner,} + + @classmethod + def from_json(cls, request_body): + + if ("title" or "owner") not in request_body: + abort(make_response({"details": "Invalid data"}, 400)) + + new_goal = cls( + title=request_body["title"], + owner=request_body["owner"]) + + return new_goal diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 480b8c4b..00000000 --- a/app/routes.py +++ /dev/null @@ -1,4 +0,0 @@ -from flask import Blueprint, request, jsonify, make_response -from app import db - -# example_bp = Blueprint('example_bp', __name__) diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py new file mode 100644 index 00000000..451b45ef --- /dev/null +++ b/app/routes/board_routes.py @@ -0,0 +1,29 @@ +from flask import Blueprint, request, jsonify, make_response +from app import db +from app.models.board import Board +# from .helpers import validate_model_instance + +# example_bp = Blueprint('example_bp', __name__) + +boards_bp = Blueprint("boards", __name__, url_prefix="/boards") + +#CREATE BOARDS +@boards_bp.route("", methods=["POST"]) +def create_board(): + request_body = request.get_json() + + new_board = Board.from_json(request_body) + + db.session.add(new_board) + db.session.commit() + + return jsonify({"board": new_board.to_json()}), 201 + +#GET all boards +@boards_bp.route("", methods=["GET"]) +def read_board(): + Boards = Board.query.all() + + boards_response = [board.to_json() for board in Boards] + + return jsonify(boards_response), 200 diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py new file mode 100644 index 00000000..e69de29b From e3cdc2703149dacaec794aaaa95d9e8ad0175333 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Tue, 28 Jun 2022 13:00:01 -0700 Subject: [PATCH 03/10] Completed endpoints for Board Model, and helper function for validating model IDs --- app/models/board.py | 2 +- app/routes/board_routes.py | 20 ++++++++++++++++++-- app/routes/helpers.py | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 app/routes/helpers.py diff --git a/app/models/board.py b/app/models/board.py index 6227324a..f40a87f0 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -17,7 +17,7 @@ def to_json(self): @classmethod def from_json(cls, request_body): - if ("title" or "owner") not in request_body: + if "title" not in request_body or "owner" not in request_body: abort(make_response({"details": "Invalid data"}, 400)) new_goal = cls( diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 451b45ef..ed449ec8 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -1,13 +1,14 @@ +from curses import BUTTON4_RELEASED from flask import Blueprint, request, jsonify, make_response from app import db from app.models.board import Board -# from .helpers import validate_model_instance +from .helpers import validate_model_instance # example_bp = Blueprint('example_bp', __name__) boards_bp = Blueprint("boards", __name__, url_prefix="/boards") -#CREATE BOARDS +#CREATE one board @boards_bp.route("", methods=["POST"]) def create_board(): request_body = request.get_json() @@ -27,3 +28,18 @@ def read_board(): boards_response = [board.to_json() for board in Boards] return jsonify(boards_response), 200 + +#GET one board +@boards_bp.route("/", methods=["GET"]) +def get_one_board(board_id): + board = validate_model_instance(Board, board_id, "board") + return jsonify({"board": board.to_json()}), 200 + +#DELETE A BOARD +@boards_bp.route("/", methods=["DELETE"]) +def delete_board(board_id): + board = validate_model_instance(Board, board_id, "board") + db.session.delete(board) + db.session.commit() + + return jsonify({"details":f'Board {board_id} "{board.title}" successfully deleted'} ), 200 diff --git a/app/routes/helpers.py b/app/routes/helpers.py new file mode 100644 index 00000000..c68be5f9 --- /dev/null +++ b/app/routes/helpers.py @@ -0,0 +1,27 @@ +from flask import abort, make_response +import requests +import os + +def validate_model_instance(cls, model_id, class_name_string): + try: + model_id = int(model_id) + except: + abort(make_response({"message":f"{class_name_string} {model_id} invalid"}, 400)) + + model = cls.query.get(model_id) + if not model: + return abort(make_response({"message":f"{class_name_string} {model_id} not found"}, 404)) + + return model + +# def send_slack_completed_message(task): + +# PATH = "https://slack.com/api/chat.postMessage" + +# BEARER_TOKEN = os.environ.get( +# "AUTH_TOKEN_SLACK") + +# query_params = {"channel" : "task-notifications", "text": f'Someone just completed the task {task.title}' } +# headers = {"authorization" : BEARER_TOKEN} + +# response_body = requests.get(PATH, params=query_params, headers=headers) \ No newline at end of file From 80c84dfed0ec8de85b5106a1d6d58f0e4a90bd1e Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Tue, 28 Jun 2022 15:11:28 -0700 Subject: [PATCH 04/10] Completed endpoint routes for Board and Card --- app/__init__.py | 7 +++---- app/models/board.py | 17 ++++++++++++----- app/models/card.py | 31 ++++++++++++++++++++++++++++++- app/routes/board_routes.py | 32 ++++++++++++++++++++++++++++++-- app/routes/card_routes.py | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 12 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index eee31feb..d886feb0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -31,10 +31,9 @@ def create_app(): # app.register_blueprint(example_bp) from app.routes.board_routes import boards_bp app.register_blueprint(boards_bp) - - #use later - # from app.routes.card_routes import cards_bp - # app.register_blueprint(cards_bp) + + from app.routes.card_routes import cards_bp + app.register_blueprint(cards_bp) CORS(app) return app diff --git a/app/models/board.py b/app/models/board.py index f40a87f0..e2d4c79a 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -1,7 +1,6 @@ from app import db -from flask import make_response, abort -# from .card import Task -# from app.routes.helpers import validate_model_instance +from flask import make_response, abort, request +from .card import Card class Board(db.Model): board_id = db.Column(db.Integer, primary_key=True, autoincrement=True) @@ -14,14 +13,22 @@ def to_json(self): "title" : self.title, "owner": self.owner,} + def link_card_to_board(self, request_body): + + new_card = Card.from_json(request_body) + if new_card not in self.cards: + self.cards.append(new_card) + + return new_card + @classmethod def from_json(cls, request_body): if "title" not in request_body or "owner" not in request_body: abort(make_response({"details": "Invalid data"}, 400)) - new_goal = cls( + new_board = cls( title=request_body["title"], owner=request_body["owner"]) - return new_goal + return new_board diff --git a/app/models/card.py b/app/models/card.py index a6632eeb..72210b60 100644 --- a/app/models/card.py +++ b/app/models/card.py @@ -1,8 +1,37 @@ from app import db +from flask import make_response, abort 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=True) - board = db.relationship("Board", back_populates="cards") \ No newline at end of file + board = db.relationship("Board", back_populates="cards") + + + def to_json(self): + return {"cardId" : self.card_id, + "message" : self.message, + "likesCount": self.likes_count, + "boardId": self.board_id} + + def update_card(self, update_body): + + # self.card_id = update_body["cardId"] + # self.message = update_body["message"] + self.likes_count = update_body["likesCount"] + # self.board_id = update_body["boardId"] + + @classmethod + def from_json(cls, request_body): + + if len(request_body["message"]) > 40: + abort(make_response({"details": "Message is too long"}, 400)) + + new_card = cls( + message=request_body["message"], + likes_count = request_body["likesCount"], + board_id = request_body["boardId"], + ) + + return new_card \ No newline at end of file diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index ed449ec8..44cb1da7 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -1,8 +1,8 @@ -from curses import BUTTON4_RELEASED from flask import Blueprint, request, jsonify, make_response from app import db from app.models.board import Board from .helpers import validate_model_instance +from app.models.card import Card # example_bp = Blueprint('example_bp', __name__) @@ -35,7 +35,7 @@ def get_one_board(board_id): board = validate_model_instance(Board, board_id, "board") return jsonify({"board": board.to_json()}), 200 -#DELETE A BOARD +#DELETE A BOARD-> optional @boards_bp.route("/", methods=["DELETE"]) def delete_board(board_id): board = validate_model_instance(Board, board_id, "board") @@ -43,3 +43,31 @@ def delete_board(board_id): db.session.commit() return jsonify({"details":f'Board {board_id} "{board.title}" successfully deleted'} ), 200 + +#POST /boards//cards +#we expect-> HTTP request body ({message, likesCount, boardId}) +@boards_bp.route("//cards", methods=["POST"]) +def add_card_to_board(board_id): + board = validate_model_instance(Board, board_id, "board") + + request_body = request.get_json() + + new_card = board.link_card_to_board(request_body) + + db.session.add(new_card) + db.session.commit() + #change return? + return jsonify({"boardId": board.board_id, "cardId": new_card.card_id}), 200 + +#GET /boards//cards +@boards_bp.route("//cards", methods=["GET"]) +def read_cards_of_board(board_id): + + board = validate_model_instance(Board, board_id, "board") + board_cards = [card.to_json() for card in board.cards] + + return jsonify({"boardId": board.board_id, + "title": board.title, + "owner": board.owner, + "cards": board_cards}), 200 + diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index e69de29b..a8e4537a 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -0,0 +1,32 @@ +from flask import Blueprint, request, jsonify, make_response +from app import db +from app.models.card import Card +from .helpers import validate_model_instance + +cards_bp = Blueprint("cards", __name__, url_prefix="/cards") + + +# DELETE /cards/ +@cards_bp.route("/", methods=["DELETE"]) +def delete_card(card_id): + card = validate_model_instance(Card, card_id, "card") + db.session.delete(card) + db.session.commit() + + return jsonify({"details":f'Card {card_id} "{card.message}" successfully deleted'} ), 200 + +# PUT /cards//like +# request body from front-end-> whole object of attributes +# ? change syntax +@cards_bp.route("//like", methods=["PUT"]) +def update_one_card(card_id): + card = validate_model_instance(Card, card_id, "card") + request_body = request.get_json() + + card.update_card(request_body) + + db.session.commit() + + return jsonify({'card':card.to_json()}), 200 + + From 12a7e880b9d18327b9ce1f9343c128391e688426 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Wed, 29 Jun 2022 10:25:27 -0700 Subject: [PATCH 05/10] Edited out comments --- app/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index d886feb0..6cfc653a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -18,7 +18,6 @@ def create_app(): "SQLALCHEMY_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 @@ -27,8 +26,7 @@ def create_app(): migrate.init_app(app, db) # Register Blueprints here - # from .routes import example_bp - # app.register_blueprint(example_bp) + from app.routes.board_routes import boards_bp app.register_blueprint(boards_bp) From 788838eeb7e6eb4de9e5f1c1d8f9a49fa1a595f5 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Wed, 29 Jun 2022 11:30:41 -0700 Subject: [PATCH 06/10] Added helper method send_slack_new_message to boards//cards endpoint --- app/routes/board_routes.py | 3 ++- app/routes/helpers.py | 14 +++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 44cb1da7..f60df58c 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -1,7 +1,7 @@ from flask import Blueprint, request, jsonify, make_response from app import db from app.models.board import Board -from .helpers import validate_model_instance +from .helpers import validate_model_instance, send_slack_new_card_message from app.models.card import Card # example_bp = Blueprint('example_bp', __name__) @@ -56,6 +56,7 @@ def add_card_to_board(board_id): db.session.add(new_card) db.session.commit() + send_slack_new_card_message(new_card) #change return? return jsonify({"boardId": board.board_id, "cardId": new_card.card_id}), 200 diff --git a/app/routes/helpers.py b/app/routes/helpers.py index c68be5f9..81d6244e 100644 --- a/app/routes/helpers.py +++ b/app/routes/helpers.py @@ -14,14 +14,14 @@ def validate_model_instance(cls, model_id, class_name_string): return model -# def send_slack_completed_message(task): +def send_slack_new_card_message(new_card): -# PATH = "https://slack.com/api/chat.postMessage" + PATH = "https://slack.com/api/chat.postMessage" -# BEARER_TOKEN = os.environ.get( -# "AUTH_TOKEN_SLACK") + BEARER_TOKEN = os.environ.get( + "AUTH_TOKEN_SLACK") -# query_params = {"channel" : "task-notifications", "text": f'Someone just completed the task {task.title}' } -# headers = {"authorization" : BEARER_TOKEN} + query_params = {"channel" : "inspir-adies", "text": f"Someone just created the card with the message '{new_card.message}'" } + headers = {"authorization" : BEARER_TOKEN} -# response_body = requests.get(PATH, params=query_params, headers=headers) \ No newline at end of file + response_body = requests.get(PATH, params=query_params, headers=headers) \ No newline at end of file From ece97563cffb6ab75aa9088d74bb848febf60475 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Wed, 29 Jun 2022 12:16:20 -0700 Subject: [PATCH 07/10] Updated HTTP response body in GET /boards//cards --- app/routes/board_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index f60df58c..1db404b0 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -58,7 +58,7 @@ def add_card_to_board(board_id): db.session.commit() send_slack_new_card_message(new_card) #change return? - return jsonify({"boardId": board.board_id, "cardId": new_card.card_id}), 200 + return jsonify({"card": new_card.to_json()}), 200 #GET /boards//cards @boards_bp.route("//cards", methods=["GET"]) From 63eb3b5a75658df4dd60fa0bdad05ddfe4958643 Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Fri, 1 Jul 2022 09:42:43 -0700 Subject: [PATCH 08/10] Updated JSON return body of GET /boards endpoint --- app/models/board.py | 9 ++++++++- app/routes/board_routes.py | 8 +++++--- app/routes/card_routes.py | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/models/board.py b/app/models/board.py index e2d4c79a..78ba223b 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -9,9 +9,16 @@ class Board(db.Model): cards = db.relationship("Card", back_populates = "board", lazy = True) def to_json(self): + + card_list = [] + for card in self.cards: + card_object = card.to_json() + card_list.append(card_object) + return {"boardId" : self.board_id, "title" : self.title, - "owner": self.owner,} + "owner": self.owner, + "cards": card_list} def link_card_to_board(self, request_body): diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 1db404b0..3d124e0c 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -18,7 +18,7 @@ def create_board(): db.session.add(new_board) db.session.commit() - return jsonify({"board": new_board.to_json()}), 201 + return jsonify({new_board.to_json()}), 201 #GET all boards @boards_bp.route("", methods=["GET"]) @@ -33,7 +33,7 @@ def read_board(): @boards_bp.route("/", methods=["GET"]) def get_one_board(board_id): board = validate_model_instance(Board, board_id, "board") - return jsonify({"board": board.to_json()}), 200 + return jsonify(board.to_json()), 200 #DELETE A BOARD-> optional @boards_bp.route("/", methods=["DELETE"]) @@ -58,7 +58,7 @@ def add_card_to_board(board_id): db.session.commit() send_slack_new_card_message(new_card) #change return? - return jsonify({"card": new_card.to_json()}), 200 + return jsonify(new_card.to_json()), 200 #GET /boards//cards @boards_bp.route("//cards", methods=["GET"]) @@ -72,3 +72,5 @@ def read_cards_of_board(board_id): "owner": board.owner, "cards": board_cards}), 200 + + diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index a8e4537a..e9d9f8af 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -27,6 +27,6 @@ def update_one_card(card_id): db.session.commit() - return jsonify({'card':card.to_json()}), 200 + return jsonify(card.to_json()), 200 From 789f766d8d624158bc02cec6e5c8754f6b7d3680 Mon Sep 17 00:00:00 2001 From: camilla Date: Tue, 19 Jul 2022 18:11:38 -0700 Subject: [PATCH 09/10] Adds config line for external deployment --- app/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 6cfc653a..004c2149 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -17,6 +17,8 @@ def create_app(): app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( "SQLALCHEMY_DATABASE_URI") + # might not need? + app.config['CORS_HEADERS'] = 'Content-Type' # Import models here for Alembic setup from app.models.board import Board @@ -29,7 +31,7 @@ def create_app(): from app.routes.board_routes import boards_bp app.register_blueprint(boards_bp) - + from app.routes.card_routes import cards_bp app.register_blueprint(cards_bp) From d13b36464e1f1e0a04480b96359d6e4aad533d0b Mon Sep 17 00:00:00 2001 From: Lauren Kleinert Date: Wed, 20 Jul 2022 11:12:42 -0700 Subject: [PATCH 10/10] fixed bugs in backend, updated return of GET all boards endpoint to not include cards --- app/models/board.py | 12 +++--------- app/routes/board_routes.py | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/app/models/board.py b/app/models/board.py index 78ba223b..f2b4de51 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -10,15 +10,9 @@ class Board(db.Model): def to_json(self): - card_list = [] - for card in self.cards: - card_object = card.to_json() - card_list.append(card_object) - - return {"boardId" : self.board_id, - "title" : self.title, - "owner": self.owner, - "cards": card_list} + return {"boardId" : self.board_id, + "title" : self.title, + "owner": self.owner} def link_card_to_board(self, request_body): diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 3d124e0c..96106c39 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -18,7 +18,7 @@ def create_board(): db.session.add(new_board) db.session.commit() - return jsonify({new_board.to_json()}), 201 + return jsonify(new_board.to_json()), 201 #GET all boards @boards_bp.route("", methods=["GET"])