From 1e10f11d9c6416aa60edbcaa0003e827a880ae85 Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 23 Dec 2022 11:53:09 -0800 Subject: [PATCH 01/21] initialized database and created model files --- app/models/board.py | 5 ++ app/models/card.py | 5 ++ migrations/README | 1 + migrations/alembic.ini | 45 ++++++++++++++++++ migrations/env.py | 96 +++++++++++++++++++++++++++++++++++++++ migrations/script.py.mako | 24 ++++++++++ 6 files changed, 176 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 diff --git a/app/models/board.py b/app/models/board.py index 147eb748..96d472a9 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -1 +1,6 @@ from app import db + +class Board(db.Model): + board_id = db.Column(db.Integer, primary_key = True) + title = db.Column(db.String) + owner = db.Column(db.String) \ No newline at end of file diff --git a/app/models/card.py b/app/models/card.py index 147eb748..7f78e2c6 100644 --- a/app/models/card.py +++ b/app/models/card.py @@ -1 +1,6 @@ from app import db + +class Card(db.Model): + card_id = db.Column(db.Integer, primary_key = True) + message = db.Column(db.String) + likes_count = db.Column(db.Integer) \ 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"} From 15a946be119d3365f0c03473292b1d976bd47241 Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 23 Dec 2022 12:08:39 -0800 Subject: [PATCH 02/21] imported models to App --- app/__init__.py | 3 +++ requirements.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) 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/requirements.txt b/requirements.txt index 76f1f000..b6b71210 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,7 +17,7 @@ Mako==1.1.4 MarkupSafe==1.1.1 packaging==20.9 pluggy==0.13.1 -psycopg2-binary==2.9.5 +psycopg2-binary==2.9.4 py==1.11.0 pycodestyle==2.6.0 pyparsing==2.4.7 From 6d6b2360f4ede7dec8fb00d73c4c57564acb3871 Mon Sep 17 00:00:00 2001 From: Carina Date: Sat, 24 Dec 2022 02:41:32 +0000 Subject: [PATCH 03/21] created initial migrations --- ...ea17117591ad_adds_board_and_card_models.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 migrations/versions/ea17117591ad_adds_board_and_card_models.py diff --git a/migrations/versions/ea17117591ad_adds_board_and_card_models.py b/migrations/versions/ea17117591ad_adds_board_and_card_models.py new file mode 100644 index 00000000..4444736a --- /dev/null +++ b/migrations/versions/ea17117591ad_adds_board_and_card_models.py @@ -0,0 +1,40 @@ +"""adds Board and Card models + +Revision ID: ea17117591ad +Revises: +Create Date: 2022-12-24 02:39:24.027858 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'ea17117591ad' +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(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('owner', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('board_id') + ) + op.create_table('card', + sa.Column('card_id', sa.Integer(), nullable=False), + sa.Column('message', sa.String(), nullable=True), + sa.Column('likes_count', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('card_id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('card') + op.drop_table('board') + # ### end Alembic commands ### From 672c72c6d0cbb93bcd496927628723b47cb3c320 Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 3 Jan 2023 11:29:24 -0800 Subject: [PATCH 04/21] new board and card models --- migrations/versions/b24701033da7_.py | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 migrations/versions/b24701033da7_.py diff --git a/migrations/versions/b24701033da7_.py b/migrations/versions/b24701033da7_.py new file mode 100644 index 00000000..e26c2c4d --- /dev/null +++ b/migrations/versions/b24701033da7_.py @@ -0,0 +1,40 @@ +"""empty message + +Revision ID: b24701033da7 +Revises: +Create Date: 2023-01-03 11:27:05.343203 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b24701033da7' +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(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('owner', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('board_id') + ) + op.create_table('card', + sa.Column('card_id', sa.Integer(), nullable=False), + sa.Column('message', sa.String(), nullable=True), + sa.Column('likes_count', sa.Integer(), nullable=True), + sa.PrimaryKeyConstraint('card_id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('card') + op.drop_table('board') + # ### end Alembic commands ### From e5249aa22afcc84d9d41107a12cf11636e31c0c4 Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 3 Jan 2023 12:14:45 -0800 Subject: [PATCH 05/21] created GET and POST routes for Board --- app/__init__.py | 2 ++ app/routes.py | 32 ++++++++++++++++++++++++++++++++ app/routes/board_routes.py | 36 ++++++++++++++++++++++++++++++++++++ app/routes/card_routes.py | 4 ++++ 4 files changed, 74 insertions(+) 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..20f573ed 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,6 +29,8 @@ def create_app(): # Register Blueprints here # from .routes import example_bp # app.register_blueprint(example_bp) + from .routes import boards_bp + app.register_blueprint(boards_bp) CORS(app) return app diff --git a/app/routes.py b/app/routes.py index 480b8c4b..8c964bb1 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,36 @@ from flask import Blueprint, request, jsonify, make_response from app import db +from app.models.board import Board +# from app.models.card import Card # example_bp = Blueprint('example_bp', __name__) +boards_bp = Blueprint("boards", __name__, url_prefix = "/boards") + +# GET endpoint to get all boards +@boards_bp.route("", methods = ["GET"]) +def get_all_boards(): + boards = Board.query.all() + boards_response = [] + for board in boards: + boards_response.append( + { + "board_id": board.board_id, + "title": board.title, + "owner": board.owner + } + ) + return jsonify(boards_response) + +# POST create a new board +@boards_bp.route("", methods = ["POST"]) +def create_board(): + request_body = request.get_json() + new_board = Board( + title = request_body["title"], + owner = request_body["owner"], + ) + + db.session.add(new_board) + db.session.commit() + + return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) \ No newline at end of file diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py new file mode 100644 index 00000000..8c964bb1 --- /dev/null +++ b/app/routes/board_routes.py @@ -0,0 +1,36 @@ +from flask import Blueprint, request, jsonify, make_response +from app import db +from app.models.board import Board +# from app.models.card import Card + +# example_bp = Blueprint('example_bp', __name__) +boards_bp = Blueprint("boards", __name__, url_prefix = "/boards") + +# GET endpoint to get all boards +@boards_bp.route("", methods = ["GET"]) +def get_all_boards(): + boards = Board.query.all() + boards_response = [] + for board in boards: + boards_response.append( + { + "board_id": board.board_id, + "title": board.title, + "owner": board.owner + } + ) + return jsonify(boards_response) + +# POST create a new board +@boards_bp.route("", methods = ["POST"]) +def create_board(): + request_body = request.get_json() + new_board = Board( + title = request_body["title"], + owner = request_body["owner"], + ) + + db.session.add(new_board) + db.session.commit() + + return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) \ No newline at end of file diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py new file mode 100644 index 00000000..e35ebf2e --- /dev/null +++ b/app/routes/card_routes.py @@ -0,0 +1,4 @@ +from flask import Blueprint, request, jsonify, make_response +from app import db + +# example_bp = Blueprint('example_bp', __name__) \ No newline at end of file From b6628b7437ea347ec14efebc2f873880fa882823 Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 6 Jan 2023 11:08:31 -0800 Subject: [PATCH 06/21] fixed routes module bug Co-authored-by: guaiguaiyang --- app/__init__.py | 2 +- app/routes/__init__.py | 0 app/routes/board_routes.py | 1 + ...ea17117591ad_adds_board_and_card_models.py | 40 ------------------- 4 files changed, 2 insertions(+), 41 deletions(-) create mode 100644 app/routes/__init__.py delete mode 100644 migrations/versions/ea17117591ad_adds_board_and_card_models.py diff --git a/app/__init__.py b/app/__init__.py index 20f573ed..44988ddd 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,7 +29,7 @@ def create_app(): # Register Blueprints here # from .routes import example_bp # app.register_blueprint(example_bp) - from .routes import boards_bp + from .routes.board_routes import boards_bp app.register_blueprint(boards_bp) CORS(app) 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 index 8c964bb1..85e1ce6a 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -1,6 +1,7 @@ from flask import Blueprint, request, jsonify, make_response from app import db from app.models.board import Board + # from app.models.card import Card # example_bp = Blueprint('example_bp', __name__) diff --git a/migrations/versions/ea17117591ad_adds_board_and_card_models.py b/migrations/versions/ea17117591ad_adds_board_and_card_models.py deleted file mode 100644 index 4444736a..00000000 --- a/migrations/versions/ea17117591ad_adds_board_and_card_models.py +++ /dev/null @@ -1,40 +0,0 @@ -"""adds Board and Card models - -Revision ID: ea17117591ad -Revises: -Create Date: 2022-12-24 02:39:24.027858 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = 'ea17117591ad' -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(), nullable=False), - sa.Column('title', sa.String(), nullable=True), - sa.Column('owner', sa.String(), nullable=True), - sa.PrimaryKeyConstraint('board_id') - ) - op.create_table('card', - sa.Column('card_id', sa.Integer(), nullable=False), - sa.Column('message', sa.String(), nullable=True), - sa.Column('likes_count', sa.Integer(), nullable=True), - sa.PrimaryKeyConstraint('card_id') - ) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('card') - op.drop_table('board') - # ### end Alembic commands ### From 380de1dd44a815ef7e02cb975123945370ae49ed Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 6 Jan 2023 11:24:50 -0800 Subject: [PATCH 07/21] added get one baord, delete board endpoints --- app/routes/board_routes.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 85e1ce6a..d9eb9e3f 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -22,6 +22,18 @@ def get_all_boards(): ) return jsonify(boards_response) +#GET endpoint to get one board +@boards_bp.route("/", methods = ["GET"]) +def get_one_board(board_id): + board = Board.query.get(board_id) + return make_response(jsonify( + { + "board_id": board.board_id, + "title": board.title, + "owner": board.owner + } + ), 200) + # POST create a new board @boards_bp.route("", methods = ["POST"]) def create_board(): @@ -34,4 +46,13 @@ def create_board(): db.session.add(new_board) db.session.commit() - return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) \ No newline at end of file + return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) + +# DELETE route +@boards_bp.route("/", methods = ["DELETE"]) +def delete_board(board_id): + board = Board.query.get(board_id) + db.session.delete(board) + db.session.commit() + + return make_response(jsonify({"msg": "board successfully deleted"}), 200) \ No newline at end of file From dd0af157fa65acdb8ae32759914bfb9843e1e2c2 Mon Sep 17 00:00:00 2001 From: Carina Date: Fri, 6 Jan 2023 11:43:24 -0800 Subject: [PATCH 08/21] created GET and POST routes for cards --- app/__init__.py | 2 ++ app/routes/card_routes.py | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 44988ddd..edbbf6f0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -31,6 +31,8 @@ def create_app(): # app.register_blueprint(example_bp) from .routes.board_routes import boards_bp app.register_blueprint(boards_bp) + from .routes.card_routes import cards_bp + app.register_blueprint(cards_bp) CORS(app) return app diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index e35ebf2e..5fdb280d 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -1,4 +1,39 @@ from flask import Blueprint, request, jsonify, make_response from app import db +from app.models.card import Card -# example_bp = Blueprint('example_bp', __name__) \ No newline at end of file +# example_bp = Blueprint('example_bp', __name__) +cards_bp = Blueprint("cards", __name__, url_prefix="/cards") + +# GET all cards +@cards_bp.route("", methods = ["GET"]) +def get_all_cards(): + cards = Card.query.all() + cards_response = [] + for card in cards: + cards_response.append( + { + "card_id": card.card_id, + "message": card.message, + "likes": card.likes_count + } + ) + return jsonify(cards_response) + +# POST create new card +@cards_bp.route("", methods = ["POST"]) +def create_card(): + request_body = request.get_json() + new_card = Card( + message = request_body["message"], + likes_count = 0 + ) + + db.session.add(new_card) + db.session.commit() + + return make_response(jsonify({"card": new_card.message}), 201) + +# UPDATE heart count on a card + +#Delete \ No newline at end of file From b7e1d8ce4703223321c0334b6863b61c604bee40 Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 17 Jan 2023 11:12:32 -0800 Subject: [PATCH 09/21] added update and delete routes for Card --- app/routes/card_routes.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 5fdb280d..1d55b1a6 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -35,5 +35,17 @@ def create_card(): return make_response(jsonify({"card": new_card.message}), 201) # UPDATE heart count on a card +@cards_bp.route("/", methods = ["PATCH"]) +def update_likes(card_id): + card = Card.query.get(card_id) + card.likes_count += 1 + db.session.commit() + + -#Delete \ No newline at end of file +#Delete +@cards_bp.route("", methods = ["DELETE"]) +def delete_card(card_id): + card = Card.query.get(card_id) + db.session.delete(card) + db.session.commit() \ No newline at end of file From 1969ba130f9f268afc57a2a9391c08a6b5573a37 Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 17 Jan 2023 11:41:45 -0800 Subject: [PATCH 10/21] added one-to-many Board-Card relationship Co-authored-by: guaiguaiyang --- app/models/board.py | 4 +++- app/models/card.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/models/board.py b/app/models/board.py index 96d472a9..271bd090 100644 --- a/app/models/board.py +++ b/app/models/board.py @@ -3,4 +3,6 @@ class Board(db.Model): board_id = db.Column(db.Integer, primary_key = True) title = db.Column(db.String) - owner = db.Column(db.String) \ No newline at end of file + owner = db.Column(db.String) + + cards = db.relationship("Card", back_populates = "board") \ No newline at end of file diff --git a/app/models/card.py b/app/models/card.py index 7f78e2c6..6ac4839d 100644 --- a/app/models/card.py +++ b/app/models/card.py @@ -3,4 +3,8 @@ class Card(db.Model): card_id = db.Column(db.Integer, primary_key = True) message = db.Column(db.String) - likes_count = db.Column(db.Integer) \ No newline at end of file + likes_count = db.Column(db.Integer) + + board_id = db.Column(db.Integer, db.ForeignKey("board.id")) + board = db.relationship("Board", back_populates = "cards") + \ No newline at end of file From f3d6f7e0a803317f23d9da0016a712cb1b11fc1f Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 17 Jan 2023 11:42:28 -0800 Subject: [PATCH 11/21] modified routes to create and read cards for specific board --- app/routes/board_routes.py | 11 +++++++++++ app/routes/card_routes.py | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index d9eb9e3f..4f1ca14b 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -34,6 +34,17 @@ def get_one_board(board_id): } ), 200) +#GET endpoint to get cards for one board +@boards_bp.route("//cards", methods = ["GET"]) +def get_board_cards(board_id): + board = Board.query.get(board_id) + cards_response = [] + for card in board.cards: + cards_response.append(card) + return make_response(jsonify( + cards_response + ), 200) + # POST create a new board @boards_bp.route("", methods = ["POST"]) def create_board(): diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 1d55b1a6..61020103 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -1,6 +1,7 @@ from flask import Blueprint, request, jsonify, make_response from app import db from app.models.card import Card +from app.models.board import Board # example_bp = Blueprint('example_bp', __name__) cards_bp = Blueprint("cards", __name__, url_prefix="/cards") @@ -21,10 +22,12 @@ def get_all_cards(): return jsonify(cards_response) # POST create new card -@cards_bp.route("", methods = ["POST"]) +@cards_bp.route("/", methods = ["POST"]) def create_card(): + board = Board.query.get(board.id) request_body = request.get_json() new_card = Card( + board_id = board.id, message = request_body["message"], likes_count = 0 ) From bf7ddade7c4cf4b138efa6b1fdb41d7c61c5a20c Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 17 Jan 2023 11:54:04 -0800 Subject: [PATCH 12/21] updated board and card routes to check for valid input --- app/routes/board_routes.py | 2 ++ app/routes/card_routes.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 4f1ca14b..f26d90ca 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -49,6 +49,8 @@ def get_board_cards(board_id): @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 jsonify({"message": "Title and Owner must be specified."}, 400) new_board = Board( title = request_body["title"], owner = request_body["owner"], diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 61020103..a6d7ad1c 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -26,6 +26,12 @@ def get_all_cards(): def create_card(): board = Board.query.get(board.id) request_body = request.get_json() + + if "message" not in request_body: + return jsonify({"message": "Message cannot be blank!"}, 400) + if len(request_body.message) > 40: + return jsonify({"message": "Maximum length 40 characters."}, 400) + new_card = Card( board_id = board.id, message = request_body["message"], From 9e991446b1de5b7646995256391295b2a0a74c2c Mon Sep 17 00:00:00 2001 From: Carina Date: Tue, 17 Jan 2023 14:49:10 -0800 Subject: [PATCH 13/21] misc changes Co-authored-by: guaiguaiyang --- app/models/card.py | 2 +- app/routes/card_routes.py | 16 +++++++++------ migrations/versions/4c97697a1e3d_.py | 30 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 migrations/versions/4c97697a1e3d_.py diff --git a/app/models/card.py b/app/models/card.py index 6ac4839d..adae9bcc 100644 --- a/app/models/card.py +++ b/app/models/card.py @@ -5,6 +5,6 @@ class Card(db.Model): message = db.Column(db.String) likes_count = db.Column(db.Integer) - board_id = db.Column(db.Integer, db.ForeignKey("board.id")) + board_id = db.Column(db.Integer, db.ForeignKey("board.board_id")) board = db.relationship("Board", back_populates = "cards") \ No newline at end of file diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index a6d7ad1c..c974b606 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -23,17 +23,17 @@ def get_all_cards(): # POST create new card @cards_bp.route("/", methods = ["POST"]) -def create_card(): - board = Board.query.get(board.id) +def create_card(board_id): + # board = Board.query.get(board_id) request_body = request.get_json() if "message" not in request_body: return jsonify({"message": "Message cannot be blank!"}, 400) - if len(request_body.message) > 40: + if len(request_body["message"]) > 40: return jsonify({"message": "Maximum length 40 characters."}, 400) new_card = Card( - board_id = board.id, + board_id = board_id, message = request_body["message"], likes_count = 0 ) @@ -53,8 +53,12 @@ def update_likes(card_id): #Delete -@cards_bp.route("", methods = ["DELETE"]) +@cards_bp.route("/", methods = ["DELETE"]) def delete_card(card_id): card = Card.query.get(card_id) db.session.delete(card) - db.session.commit() \ No newline at end of file + db.session.commit() + +# @cards_bp.route("", methods = ["DELETE"]) +# def delete_all_cards(): +# card = Card.query. diff --git a/migrations/versions/4c97697a1e3d_.py b/migrations/versions/4c97697a1e3d_.py new file mode 100644 index 00000000..7e936e63 --- /dev/null +++ b/migrations/versions/4c97697a1e3d_.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: 4c97697a1e3d +Revises: b24701033da7 +Create Date: 2023-01-17 14:13:12.321524 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4c97697a1e3d' +down_revision = 'b24701033da7' +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 ### From 6bab13497f0dea57bbbf515de9a6be6a2980ffc8 Mon Sep 17 00:00:00 2001 From: yangsu Date: Tue, 17 Jan 2023 22:33:48 -0800 Subject: [PATCH 14/21] update database add board_id and UPDATE heart data work --- app/routes/card_routes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index c974b606..67e26941 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -47,10 +47,12 @@ def create_card(board_id): @cards_bp.route("/", methods = ["PATCH"]) def update_likes(card_id): card = Card.query.get(card_id) - card.likes_count += 1 + request_body = request.get_json() + card.likes_count = request_body["likes_count"] + db.session.commit() - + return make_response(f"Book #{card_id} successfully updated") #Delete @cards_bp.route("/", methods = ["DELETE"]) From ab4cf2f32dcfc22c016bacb36585c5fc414001fc Mon Sep 17 00:00:00 2001 From: Carina Date: Wed, 18 Jan 2023 10:31:43 -0800 Subject: [PATCH 15/21] modified route to get all cards for one board --- app/routes/board_routes.py | 8 ++++---- app/routes/card_routes.py | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index f26d90ca..420d175e 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -40,10 +40,10 @@ def get_board_cards(board_id): board = Board.query.get(board_id) cards_response = [] for card in board.cards: - cards_response.append(card) - return make_response(jsonify( - cards_response - ), 200) + cards_response.append( + {"id": card.card_id, + "message": card.message}) + return jsonify(cards_response) # POST create a new board @boards_bp.route("", methods = ["POST"]) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 67e26941..760956cb 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -16,7 +16,8 @@ def get_all_cards(): { "card_id": card.card_id, "message": card.message, - "likes": card.likes_count + "likes": card.likes_count, + "board_id": card.board_id } ) return jsonify(cards_response) From b3175b4a0ef73e451de442aca98b285ecb89d471 Mon Sep 17 00:00:00 2001 From: yangsu Date: Wed, 18 Jan 2023 10:32:43 -0800 Subject: [PATCH 16/21] pull down code --- app/routes/board_routes.py | 2 +- app/routes/card_routes.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index f26d90ca..9d379e7c 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -34,7 +34,7 @@ def get_one_board(board_id): } ), 200) -#GET endpoint to get cards for one board +# #GET endpoint to get cards for one board @boards_bp.route("//cards", methods = ["GET"]) def get_board_cards(board_id): board = Board.query.get(board_id) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 67e26941..eae5e2be 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -20,7 +20,6 @@ def get_all_cards(): } ) return jsonify(cards_response) - # POST create new card @cards_bp.route("/", methods = ["POST"]) def create_card(board_id): From 7e4a8880feb1e948ad084b47a77393d7c393925d Mon Sep 17 00:00:00 2001 From: Carina Date: Wed, 18 Jan 2023 10:48:58 -0800 Subject: [PATCH 17/21] moved route to create new card from card_routes to board_routes --- app/routes/board_routes.py | 25 +++++++++++++++++++++++-- app/routes/card_routes.py | 34 +++++++++++++++++----------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index 420d175e..7949681c 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -1,8 +1,7 @@ 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.models.card import Card # example_bp = Blueprint('example_bp', __name__) boards_bp = Blueprint("boards", __name__, url_prefix = "/boards") @@ -61,6 +60,28 @@ def create_board(): return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) +# POST create new card +@boards_bp.route("//cards", methods = ["POST"]) +def create_card(board_id): + # board = Board.query.get(board_id) + request_body = request.get_json() + + if "message" not in request_body: + return jsonify({"message": "Message cannot be blank!"}, 400) + if len(request_body["message"]) > 40: + return jsonify({"message": "Maximum length 40 characters."}, 400) + + new_card = Card( + board_id = board_id, + message = request_body["message"], + likes_count = 0 + ) + + db.session.add(new_card) + db.session.commit() + + return make_response(jsonify({"card": new_card.message}), 201) + # DELETE route @boards_bp.route("/", methods = ["DELETE"]) def delete_board(board_id): diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index 760956cb..bfe2f9ff 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -22,27 +22,27 @@ def get_all_cards(): ) return jsonify(cards_response) -# POST create new card -@cards_bp.route("/", methods = ["POST"]) -def create_card(board_id): - # board = Board.query.get(board_id) - request_body = request.get_json() +# # POST create new card +# @cards_bp.route("/", methods = ["POST"]) +# def create_card(board_id): +# # board = Board.query.get(board_id) +# request_body = request.get_json() - if "message" not in request_body: - return jsonify({"message": "Message cannot be blank!"}, 400) - if len(request_body["message"]) > 40: - return jsonify({"message": "Maximum length 40 characters."}, 400) +# if "message" not in request_body: +# return jsonify({"message": "Message cannot be blank!"}, 400) +# if len(request_body["message"]) > 40: +# return jsonify({"message": "Maximum length 40 characters."}, 400) - new_card = Card( - board_id = board_id, - message = request_body["message"], - likes_count = 0 - ) +# new_card = Card( +# board_id = board_id, +# message = request_body["message"], +# likes_count = 0 +# ) - db.session.add(new_card) - db.session.commit() +# db.session.add(new_card) +# db.session.commit() - return make_response(jsonify({"card": new_card.message}), 201) +# return make_response(jsonify({"card": new_card.message}), 201) # UPDATE heart count on a card @cards_bp.route("/", methods = ["PATCH"]) From cf69da60bedc444b64a9fc7ebd6e54a6454b46c1 Mon Sep 17 00:00:00 2001 From: yangsu Date: Wed, 18 Jan 2023 10:50:55 -0800 Subject: [PATCH 18/21] pull down cheack --- app/routes/card_routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index ffe94b7d..0b26fe56 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -44,7 +44,7 @@ def create_card(board_id): return make_response(jsonify({"card": new_card.message}), 201) # UPDATE heart count on a card -@cards_bp.route("/", methods = ["PATCH"]) +@cards_bp.route("/", methods = ["PUT"]) def update_likes(card_id): card = Card.query.get(card_id) request_body = request.get_json() From 78d7b79591e6660e12b82141413faa91b81fcddd Mon Sep 17 00:00:00 2001 From: Carina Date: Wed, 18 Jan 2023 10:56:09 -0800 Subject: [PATCH 19/21] update delete card route --- app/routes/card_routes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index bfe2f9ff..a097b6ab 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -53,7 +53,7 @@ def update_likes(card_id): db.session.commit() - return make_response(f"Book #{card_id} successfully updated") + return make_response(f"Card #{card_id} successfully updated") #Delete @cards_bp.route("/", methods = ["DELETE"]) @@ -61,6 +61,7 @@ def delete_card(card_id): card = Card.query.get(card_id) db.session.delete(card) db.session.commit() + return make_response(f"Card #{card_id} successfully deleted") # @cards_bp.route("", methods = ["DELETE"]) # def delete_all_cards(): From 6c1598740c3b522e4e0f96c2735b76d07c06f7d3 Mon Sep 17 00:00:00 2001 From: Carina Date: Wed, 18 Jan 2023 11:09:42 -0800 Subject: [PATCH 20/21] cleanup --- app/routes.py | 36 ------------------------------------ app/routes/board_routes.py | 1 - app/routes/card_routes.py | 27 --------------------------- 3 files changed, 64 deletions(-) delete mode 100644 app/routes.py diff --git a/app/routes.py b/app/routes.py deleted file mode 100644 index 8c964bb1..00000000 --- a/app/routes.py +++ /dev/null @@ -1,36 +0,0 @@ -from flask import Blueprint, request, jsonify, make_response -from app import db -from app.models.board import Board -# from app.models.card import Card - -# example_bp = Blueprint('example_bp', __name__) -boards_bp = Blueprint("boards", __name__, url_prefix = "/boards") - -# GET endpoint to get all boards -@boards_bp.route("", methods = ["GET"]) -def get_all_boards(): - boards = Board.query.all() - boards_response = [] - for board in boards: - boards_response.append( - { - "board_id": board.board_id, - "title": board.title, - "owner": board.owner - } - ) - return jsonify(boards_response) - -# POST create a new board -@boards_bp.route("", methods = ["POST"]) -def create_board(): - request_body = request.get_json() - new_board = Board( - title = request_body["title"], - owner = request_body["owner"], - ) - - db.session.add(new_board) - db.session.commit() - - return make_response(jsonify({"board": new_board.title, "owner": new_board.owner}), 201) \ No newline at end of file diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index aa0fc615..f5b9ea8a 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -3,7 +3,6 @@ from app.models.board import Board from app.models.card import Card -# example_bp = Blueprint('example_bp', __name__) boards_bp = Blueprint("boards", __name__, url_prefix = "/boards") # GET endpoint to get all boards diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index a3340eed..fe885d03 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -3,7 +3,6 @@ from app.models.card import Card from app.models.board import Board -# example_bp = Blueprint('example_bp', __name__) cards_bp = Blueprint("cards", __name__, url_prefix="/cards") # GET all cards @@ -22,28 +21,6 @@ def get_all_cards(): ) return jsonify(cards_response) -# # POST create new card -# @cards_bp.route("/", methods = ["POST"]) -# def create_card(board_id): -# # board = Board.query.get(board_id) -# request_body = request.get_json() - -# if "message" not in request_body: -# return jsonify({"message": "Message cannot be blank!"}, 400) -# if len(request_body["message"]) > 40: -# return jsonify({"message": "Maximum length 40 characters."}, 400) - -# new_card = Card( -# board_id = board_id, -# message = request_body["message"], -# likes_count = 0 -# ) - -# db.session.add(new_card) -# db.session.commit() - -# return make_response(jsonify({"card": new_card.message}), 201) - # UPDATE heart count on a card @cards_bp.route("/", methods = ["PUT"]) def update_likes(card_id): @@ -62,7 +39,3 @@ def delete_card(card_id): db.session.delete(card) db.session.commit() return make_response(f"Card #{card_id} successfully deleted") - -# @cards_bp.route("", methods = ["DELETE"]) -# def delete_all_cards(): -# card = Card.query. From 2f47eb83131a1c6413e2286d14df10745bb47edd Mon Sep 17 00:00:00 2001 From: Carina Date: Thu, 19 Jan 2023 12:24:28 -0800 Subject: [PATCH 21/21] fixed card id thingy --- app/routes/board_routes.py | 2 +- app/routes/card_routes.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/routes/board_routes.py b/app/routes/board_routes.py index f5b9ea8a..5142131e 100644 --- a/app/routes/board_routes.py +++ b/app/routes/board_routes.py @@ -39,7 +39,7 @@ def get_board_cards(board_id): cards_response = [] for card in board.cards: cards_response.append( - {"id": card.card_id, + {"card_id": card.card_id, "message": card.message}) return jsonify(cards_response) diff --git a/app/routes/card_routes.py b/app/routes/card_routes.py index fe885d03..a9114663 100644 --- a/app/routes/card_routes.py +++ b/app/routes/card_routes.py @@ -38,4 +38,13 @@ def delete_card(card_id): card = Card.query.get(card_id) db.session.delete(card) db.session.commit() - return make_response(f"Card #{card_id} successfully deleted") + return make_response(f"Card #{card_id} successfully deleted", 200) + +# Delete all cards +@cards_bp.route("", methods = ["DELETE"]) +def delete_all_cards(): + cards = Card.query.all() + for card in cards: + db.session.delete(card) + db.session.commit() + return make_response("All cards successfully deleted") \ No newline at end of file