From 1731c596a77be248a73e77d7589dbe86436cce87 Mon Sep 17 00:00:00 2001 From: Melinda Date: Sat, 30 Oct 2021 21:18:39 -0700 Subject: [PATCH 01/13] create routes for tasks and task/index --- app/__init__.py | 9 +++ app/models/task.py | 8 +++ app/routes.py | 57 ++++++++++++++++- migrations/README | 1 + migrations/alembic.ini | 45 +++++++++++++ migrations/env.py | 96 ++++++++++++++++++++++++++++ migrations/script.py.mako | 24 +++++++ migrations/versions/e7e1694fdd68_.py | 39 +++++++++++ 8 files changed, 278 insertions(+), 1 deletion(-) 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/e7e1694fdd68_.py diff --git a/app/__init__.py b/app/__init__.py index 2764c4cc8..f74814b23 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -14,6 +14,15 @@ def create_app(test_config=None): app = Flask(__name__) app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + # import models here + from app.models.task import Task + db.init_app(app) + migrate.init_app(app, db) + + # register blueprint here + from .routes import tasks_bp + app.register_blueprint(tasks_bp) + if test_config is None: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( "SQLALCHEMY_DATABASE_URI") diff --git a/app/models/task.py b/app/models/task.py index 39c89cd16..4dc32ceb2 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -1,6 +1,14 @@ from flask import current_app from app import db +# task_id: a primary key for each task +# title: text to name the task +# description: text to describe the task +# completed_at: a datetime that has the date that a task is completed on. Can be nullable, and contain a null value. A task with a null value for completed_at has not been completed. class Task(db.Model): task_id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.String) + description = db.Column(db.String) + completed_at = db.Column(db.DateTime) + diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..4b9fa41ab 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,57 @@ -from flask import Blueprint +from app.models.task import Task +from app import db +from flask import Blueprint, jsonify, make_response, request + +tasks_bp = Blueprint("tasks_bp", __name__, url_prefix="/tasks") + +@tasks_bp.route("", methods=["GET", "POST"]) +def handle_tasks(): + if request.method == "GET": + tasks = Task.query.all() + tasks_response = [] + for task in tasks: + has_complete = task.completed_at + tasks_response.append( + { + "description": task.description, + "id": task.task_id, + "is_complete": False if has_complete == None else has_complete, + "title": task.title, + } + ) + return jsonify(tasks_response) + elif request.method == "POST": + request_body = request.get_json() + if "title" not in request_body or "description" not in request_body: + return make_response("Invalid Request", 400) + + new_task = Task( + title=request_body["title"], + description=request_body["description"], + completed_at=request_body["completed_at"] + ) + db.session.add(new_task) + db.session.commit() + + return "201 CREATED",201 + + +@tasks_bp.route("/", methods=["GET"]) +def handle_one_task(task_id): + task_id = int(task_id) + task = Task.query.get_or_404(task_id) + + if request.method == "GET": + task_response = [] + task_response.append( + { + "description": task.description, + "id": task.task_id, + "is_complete": task.completed_at, + "title": task.title, + } + ) + + return jsonify(task_response) + diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /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 000000000..f8ed4801f --- /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 000000000..8b3fb3353 --- /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 000000000..2c0156303 --- /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/e7e1694fdd68_.py b/migrations/versions/e7e1694fdd68_.py new file mode 100644 index 000000000..1676f969f --- /dev/null +++ b/migrations/versions/e7e1694fdd68_.py @@ -0,0 +1,39 @@ +"""empty message + +Revision ID: e7e1694fdd68 +Revises: +Create Date: 2021-10-29 22:38:53.340177 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'e7e1694fdd68' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('goal', + sa.Column('goal_id', sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('goal_id') + ) + op.create_table('task', + sa.Column('task_id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('completed_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('task_id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('task') + op.drop_table('goal') + # ### end Alembic commands ### From 0dbeff59bd0ea8ceae489a671a88b2311a43a88a Mon Sep 17 00:00:00 2001 From: Melinda Date: Sat, 30 Oct 2021 21:39:18 -0700 Subject: [PATCH 02/13] PUT request in one task --- app/routes.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 4b9fa41ab..5773a8000 100644 --- a/app/routes.py +++ b/app/routes.py @@ -36,7 +36,7 @@ def handle_tasks(): return "201 CREATED",201 -@tasks_bp.route("/", methods=["GET"]) +@tasks_bp.route("/", methods=["GET", "PUT"]) def handle_one_task(task_id): task_id = int(task_id) task = Task.query.get_or_404(task_id) @@ -51,6 +51,16 @@ def handle_one_task(task_id): "title": task.title, } ) + elif request.method == "PUT": + form_data = request.get_json() + + task.title = form_data["title"] + task.description = form_data["description"] + + + db.session.commit() + + return make_response(f"200 OK", 200) return jsonify(task_response) From 9483d5e6918f6315b57dff6c223c8fed006b9969 Mon Sep 17 00:00:00 2001 From: Melinda Date: Sat, 30 Oct 2021 21:45:08 -0700 Subject: [PATCH 03/13] add back deleted return --- app/routes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 5773a8000..456363832 100644 --- a/app/routes.py +++ b/app/routes.py @@ -43,14 +43,16 @@ def handle_one_task(task_id): if request.method == "GET": task_response = [] + has_complete = task.completed_at task_response.append( { "description": task.description, "id": task.task_id, - "is_complete": task.completed_at, + "is_complete": False if has_complete == None else has_complete, "title": task.title, } ) + return jsonify(task_response) elif request.method == "PUT": form_data = request.get_json() From bd8083fa42edf687e80d0deb02856d8f915ca086 Mon Sep 17 00:00:00 2001 From: Melinda Date: Wed, 3 Nov 2021 16:48:22 -0700 Subject: [PATCH 04/13] passed wave 1 tests --- app/__init__.py | 11 ++- app/models/task.py | 2 +- app/routes.py | 67 +++++++++++++++---- .../{e7e1694fdd68_.py => daed2d606291_.py} | 6 +- 4 files changed, 63 insertions(+), 23 deletions(-) rename migrations/versions/{e7e1694fdd68_.py => daed2d606291_.py} (90%) diff --git a/app/__init__.py b/app/__init__.py index f74814b23..e75fbf5a5 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,13 +15,9 @@ def create_app(test_config=None): app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False # import models here - from app.models.task import Task - db.init_app(app) - migrate.init_app(app, db) + - # register blueprint here - from .routes import tasks_bp - app.register_blueprint(tasks_bp) + if test_config is None: app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( @@ -39,5 +35,8 @@ def create_app(test_config=None): migrate.init_app(app, db) # Register Blueprints here + + from .routes import tasks_bp + app.register_blueprint(tasks_bp) return app diff --git a/app/models/task.py b/app/models/task.py index 4dc32ceb2..84acc282e 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -10,5 +10,5 @@ class Task(db.Model): task_id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) description = db.Column(db.String) - completed_at = db.Column(db.DateTime) + completed_at = db.Column(db.DateTime,nullable=True) diff --git a/app/routes.py b/app/routes.py index 456363832..352c1817f 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,13 +1,19 @@ +from flask.wrappers import Response from app.models.task import Task from app import db from flask import Blueprint, jsonify, make_response, request +# handle_tasks handles GET and POST requests for the /tasks endpoint + + tasks_bp = Blueprint("tasks_bp", __name__, url_prefix="/tasks") @tasks_bp.route("", methods=["GET", "POST"]) def handle_tasks(): +# Wave 1: Get Tasks: Getting Saved Tasks if request.method == "GET": tasks = Task.query.all() +#Wave 1: Get Tasks: No Saved Tasks tasks_response = [] for task in tasks: has_complete = task.completed_at @@ -20,10 +26,15 @@ def handle_tasks(): } ) return jsonify(tasks_response) +# Wave 1: Create a Task: Valid Task With null completed_at elif request.method == "POST": request_body = request.get_json() - if "title" not in request_body or "description" not in request_body: - return make_response("Invalid Request", 400) +#Wave 1: Create A Task: Missing Title + if "title" not in request_body or "description" not in request_body or "completed_at" not in request_body: + response_body= { + "details": "Invalid data" + } + return make_response(response_body, 400) new_task = Task( title=request_body["title"], @@ -32,27 +43,40 @@ def handle_tasks(): ) db.session.add(new_task) db.session.commit() + +#Wave 1: Create A Task: Valid Task with null completed_at 201 CREATED - return "201 CREATED",201 + request_body= { + "task": { + "id": new_task.task_id, + "title": new_task.title, + "description": new_task.description, + "is_complete": False if new_task.completed_at == None else new_task.completed_at + } + } + return request_body,201 -@tasks_bp.route("/", methods=["GET", "PUT"]) +# handle_one_task handles GET,PUT and DELETE requests for the tasks/task_id endpoint +@tasks_bp.route("/", methods=["GET", "PUT", "DELETE"]) def handle_one_task(task_id): task_id = int(task_id) task = Task.query.get_or_404(task_id) - +#Wave 1: Get One Task: One Saved Task if request.method == "GET": - task_response = [] has_complete = task.completed_at - task_response.append( - { - "description": task.description, + task_response={ + "task": { "id": task.task_id, - "is_complete": False if has_complete == None else has_complete, "title": task.title, + "description": task.description, + "is_complete": False if has_complete == None else has_complete, + } - ) + } + return jsonify(task_response) +#Wave 1: Update Task, #Wave 1 Update Task: No Matching Task elif request.method == "PUT": form_data = request.get_json() @@ -61,9 +85,26 @@ def handle_one_task(task_id): db.session.commit() +#Wave 1: Update Task 200 OK + request_body= { + "task": { + "id": task.task_id, + "title": task.title, + "description": task.description, + "is_complete": False if task.completed_at == None else task.completed_at + } + } - return make_response(f"200 OK", 200) + return make_response(request_body, 200) +#Wave 1 Delete Task: Deleting A Task, #Wave 1: Delete Task: No Matching Task + elif request.method == "DELETE": + db.session.delete(task) + db.session.commit() + response = { + "details": f'Task {task.task_id} "{task.title}" successfully deleted' + } + json_response = jsonify(response) + return make_response(json_response, 200) - return jsonify(task_response) diff --git a/migrations/versions/e7e1694fdd68_.py b/migrations/versions/daed2d606291_.py similarity index 90% rename from migrations/versions/e7e1694fdd68_.py rename to migrations/versions/daed2d606291_.py index 1676f969f..555080bd5 100644 --- a/migrations/versions/e7e1694fdd68_.py +++ b/migrations/versions/daed2d606291_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: e7e1694fdd68 +Revision ID: daed2d606291 Revises: -Create Date: 2021-10-29 22:38:53.340177 +Create Date: 2021-11-02 11:00:20.230195 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = 'e7e1694fdd68' +revision = 'daed2d606291' down_revision = None branch_labels = None depends_on = None From 06b9bf9eb4062b49950f168ebd7ee1ffb6cd2638 Mon Sep 17 00:00:00 2001 From: Melinda Date: Wed, 3 Nov 2021 18:25:17 -0700 Subject: [PATCH 05/13] passed wave 2 --- app/routes.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 352c1817f..848a94c8c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -12,7 +12,13 @@ def handle_tasks(): # Wave 1: Get Tasks: Getting Saved Tasks if request.method == "GET": - tasks = Task.query.all() + sort = request.args.get("sort") + if sort == "asc": + tasks = Task.query.order_by(Task.title) + elif sort == "desc": + tasks = Task.query.order_by(Task.title.desc()) + else: + tasks = Task.query.all() #Wave 1: Get Tasks: No Saved Tasks tasks_response = [] for task in tasks: From 3b30b7f9c172052b038a5a32fdc799e0576b53d4 Mon Sep 17 00:00:00 2001 From: Melinda Date: Thu, 4 Nov 2021 18:33:22 -0700 Subject: [PATCH 06/13] completed wave 3 --- app/models/task.py | 15 ++++++++++++++ app/routes.py | 50 +++++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/app/models/task.py b/app/models/task.py index 84acc282e..19a4a1475 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -12,3 +12,18 @@ class Task(db.Model): description = db.Column(db.String) completed_at = db.Column(db.DateTime,nullable=True) + def to_dict(self): + return{ + + "id": self.task_id, + "title": self.title, + "description": self.description, + "is_complete": self.check_for_complete_task() + + } + + def check_for_complete_task(self): + if self.completed_at: + return True + return False + diff --git a/app/routes.py b/app/routes.py index 848a94c8c..917db32f8 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,12 +1,18 @@ from flask.wrappers import Response from app.models.task import Task from app import db -from flask import Blueprint, jsonify, make_response, request +from flask import Blueprint, jsonify, make_response, request, abort +from datetime import date # handle_tasks handles GET and POST requests for the /tasks endpoint tasks_bp = Blueprint("tasks_bp", __name__, url_prefix="/tasks") +def valid_int(number,parameter_type): + try: + int(number) + except: + abort(make_response({"error":f"{parameter_type} must be an int"},400)) @tasks_bp.route("", methods=["GET", "POST"]) def handle_tasks(): @@ -52,21 +58,12 @@ def handle_tasks(): #Wave 1: Create A Task: Valid Task with null completed_at 201 CREATED - request_body= { - "task": { - "id": new_task.task_id, - "title": new_task.title, - "description": new_task.description, - "is_complete": False if new_task.completed_at == None else new_task.completed_at - } - } - - return request_body,201 + return jsonify({"task":new_task.to_dict()}),201 # handle_one_task handles GET,PUT and DELETE requests for the tasks/task_id endpoint @tasks_bp.route("/", methods=["GET", "PUT", "DELETE"]) def handle_one_task(task_id): - task_id = int(task_id) + valid_int(task_id,"task_id") task = Task.query.get_or_404(task_id) #Wave 1: Get One Task: One Saved Task if request.method == "GET": @@ -82,7 +79,7 @@ def handle_one_task(task_id): } return jsonify(task_response) -#Wave 1: Update Task, #Wave 1 Update Task: No Matching Task +#Wave 1: Update Task, #Wave 1 Update Task: No Matching Task, Update Task 200 OK elif request.method == "PUT": form_data = request.get_json() @@ -91,17 +88,8 @@ def handle_one_task(task_id): db.session.commit() -#Wave 1: Update Task 200 OK - request_body= { - "task": { - "id": task.task_id, - "title": task.title, - "description": task.description, - "is_complete": False if task.completed_at == None else task.completed_at - } - } + return jsonify({"task":task.to_dict()}),200 - return make_response(request_body, 200) #Wave 1 Delete Task: Deleting A Task, #Wave 1: Delete Task: No Matching Task elif request.method == "DELETE": db.session.delete(task) @@ -113,4 +101,20 @@ def handle_one_task(task_id): return make_response(json_response, 200) +#Wave 3 +@tasks_bp.route("//mark_complete", methods=["PATCH"]) +def handle_completed_task(task_id): + valid_int(task_id,"task_id") + task = Task.query.get_or_404(task_id) + task.completed_at = date.today() + db.session.commit() + return jsonify ({"task":task.to_dict()}),200 + +@tasks_bp.route("//mark_incomplete", methods=["PATCH"]) +def handle_incompleted_task(task_id): + valid_int(task_id,"task_id") + task = Task.query.get_or_404(task_id) + task.completed_at = None + db.session.commit() + return jsonify ({"task":task.to_dict()}),200 From 460b2bae72025f036fde9759d089a39553dab9aa Mon Sep 17 00:00:00 2001 From: Melinda Date: Mon, 8 Nov 2021 17:06:06 -0800 Subject: [PATCH 07/13] making a slack notification --- app/routes.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 917db32f8..e7435e259 100644 --- a/app/routes.py +++ b/app/routes.py @@ -3,6 +3,9 @@ from app import db from flask import Blueprint, jsonify, make_response, request, abort from datetime import date +import os +import requests +from dotenv import load_dotenv # handle_tasks handles GET and POST requests for the /tasks endpoint @@ -100,6 +103,17 @@ def handle_one_task(task_id): json_response = jsonify(response) return make_response(json_response, 200) +def slack_bot(title): + query_path = { + "channel": "melinda-bot", + "text": f"Someone completed the task {title}" + } + header = { + "Authorization": f"Bearer {os.environ.get('BOT')}" + } + response = requests.post("https://slack.com/api/chat.postMessage",params = query_path, headers = header) + return response.json() + #Wave 3 @tasks_bp.route("//mark_complete", methods=["PATCH"]) @@ -108,9 +122,11 @@ def handle_completed_task(task_id): task = Task.query.get_or_404(task_id) task.completed_at = date.today() db.session.commit() + slack_bot(task.title) return jsonify ({"task":task.to_dict()}),200 + -@tasks_bp.route("//mark_incomplete", methods=["PATCH"]) +@tasks_bp.route("//mark_incomplete", methods=["PATCH"]) def handle_incompleted_task(task_id): valid_int(task_id,"task_id") task = Task.query.get_or_404(task_id) From c9617244c9895e916e99ad8dee8ff1df756ade24 Mon Sep 17 00:00:00 2001 From: Melinda Date: Mon, 8 Nov 2021 17:23:10 -0800 Subject: [PATCH 08/13] added to the goal model --- app/models/goal.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/models/goal.py b/app/models/goal.py index 8cad278f8..f1dd812ee 100644 --- a/app/models/goal.py +++ b/app/models/goal.py @@ -4,3 +4,13 @@ class Goal(db.Model): goal_id = db.Column(db.Integer, primary_key=True) + title = db.Column(db.String) + + def to_dict(self): + return{ + + "goal_id": self.goal_id, + "title": self.title, + + } + From 7d67044f0f10ba523e0b7463dc312716101ff29e Mon Sep 17 00:00:00 2001 From: Melinda Date: Thu, 11 Nov 2021 08:31:19 -0800 Subject: [PATCH 09/13] passed all wave 5 test --- app/__init__.py | 3 + app/routes.py | 98 +++++++++++++++++++++++++++- migrations/versions/71cbf284bfc7_.py | 28 ++++++++ tests/test_wave_05.py | 42 +++++++----- 4 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 migrations/versions/71cbf284bfc7_.py diff --git a/app/__init__.py b/app/__init__.py index e75fbf5a5..f818895f8 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -39,4 +39,7 @@ def create_app(test_config=None): from .routes import tasks_bp app.register_blueprint(tasks_bp) + from .routes import goals_bp + app.register_blueprint(goals_bp) + return app diff --git a/app/routes.py b/app/routes.py index e7435e259..fe1c5aa71 100644 --- a/app/routes.py +++ b/app/routes.py @@ -6,6 +6,7 @@ import os import requests from dotenv import load_dotenv +from app.models.goal import Goal # handle_tasks handles GET and POST requests for the /tasks endpoint @@ -68,7 +69,7 @@ def handle_tasks(): def handle_one_task(task_id): valid_int(task_id,"task_id") task = Task.query.get_or_404(task_id) -#Wave 1: Get One Task: One Saved Task +# Wave 1: Get One Task: One Saved Task if request.method == "GET": has_complete = task.completed_at task_response={ @@ -134,3 +135,98 @@ def handle_incompleted_task(task_id): db.session.commit() return jsonify ({"task":task.to_dict()}),200 + +# Wave 5 Creating a Goal Model Blueprint +goals_bp = Blueprint("goals_bp", __name__, url_prefix="/goals") + +# Wave 5 Create A Goal: Valid Goal +@goals_bp.route("", methods=["POST"]) +def handle_post_goals(): + + request_body = request.get_json() + + if "title" not in request_body: + response_body= { + "details": "Invalid data" + } + return make_response(response_body, 400) + + new_goal = Goal( + title = request_body["title"] + ) + db.session.add(new_goal) + db.session.commit() + response_body = { + "goal": { + "id": new_goal.goal_id, + "title": new_goal.title + } + } + + return jsonify(response_body), 201 + +# Wave 5 Get Goals: Getting Saved Goals +@goals_bp.route("", methods=["GET"]) +def handle_get_goals(): + goals = Goal.query.all() + goals_response = [] + for goal in goals: + goals_response.append( + { + + "id": goal.goal_id, + "title": goal.title, + } + ) + return jsonify(goals_response) + +# Wave 5 Get One Goal: Getting One Saved Goal/No Matching Goal +@goals_bp.route("/", methods=["GET"]) +def handle_get_one_goal(goal_id): + # Need to query through the data base + goal = Goal.query.get_or_404(goal_id) + # Need to prepare response to give to client + goal_response = { + "goal": { + "id": goal.goal_id, + "title": goal.title, + } + } + return jsonify(goal_response) + +# Wave 5 Update Goal: Update Goal/No Matching Goal +@goals_bp.route("/", methods=["PUT"]) +def handle_update_one_goal(goal_id): + goal = Goal.query.get_or_404(goal_id) + form_data = request.get_json() + if "title" not in form_data: + response_body= { + "details": "title required" + } + return make_response(response_body, 400) + goal.title = form_data["title"] + + db.session.commit() + return jsonify({"goal":goal.to_dict()}),200 + +# Wave 5 Deleting A Goal: Deleting A Goal/No Matching Goal +@goals_bp.route("/", methods=["DELETE"]) +def handle_delete_one_goal(goal_id): + goal = Goal.query.get_or_404(goal_id) + db.session.delete(goal) + db.session.commit() + response = { + "details": f'Goal {goal.goal_id} "{goal.title}" successfully deleted' + } + json_response = jsonify(response) + return make_response(json_response, 200) + + + + + + + + + + diff --git a/migrations/versions/71cbf284bfc7_.py b/migrations/versions/71cbf284bfc7_.py new file mode 100644 index 000000000..9d6087113 --- /dev/null +++ b/migrations/versions/71cbf284bfc7_.py @@ -0,0 +1,28 @@ +"""empty message + +Revision ID: 71cbf284bfc7 +Revises: daed2d606291 +Create Date: 2021-11-08 17:24:12.393653 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '71cbf284bfc7' +down_revision = 'daed2d606291' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('goal', sa.Column('title', sa.String(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('goal', 'title') + # ### end Alembic commands ### diff --git a/tests/test_wave_05.py b/tests/test_wave_05.py index 6ba60c6fa..6838ee096 100644 --- a/tests/test_wave_05.py +++ b/tests/test_wave_05.py @@ -41,17 +41,17 @@ def test_get_goal(client, one_goal): } } -@pytest.mark.skip(reason="test to be completed by student") +#@pytest.mark.skip(reason="test to be completed by student") def test_get_goal_not_found(client): - pass + # Act response = client.get("/goals/1") response_body = response.get_json() # Assert # ---- Complete Test ---- - # assertion 1 goes here - # assertion 2 goes here + assert response.status_code == 404 + assert response_body == None # ---- Complete Test ---- def test_create_goal(client): @@ -71,29 +71,37 @@ def test_create_goal(client): } } -@pytest.mark.skip(reason="test to be completed by student") +#@pytest.mark.skip(reason="test to be completed by student") def test_update_goal(client, one_goal): pass - # Act + response = client.put("goals/1", json={"title": "Updated Goal"}) + response_body = response.get_json() # ---- Complete Act Here ---- # Assert # ---- Complete Assertions Here ---- - # assertion 1 goes here - # assertion 2 goes here - # assertion 3 goes here + assert response.status_code == 200 + assert "goal" in response_body + assert response_body == { + "goal": { + "goal_id": 1, + "title": "Updated Goal" + } + } # ---- Complete Assertions Here ---- -@pytest.mark.skip(reason="test to be completed by student") +#@pytest.mark.skip(reason="test to be completed by student") def test_update_goal_not_found(client): pass # Act # ---- Complete Act Here ---- + response = client.put("goals/1", json={"title": "Updated Goal"}) + response_body = response.get_json() # Assert # ---- Complete Assertions Here ---- - # assertion 1 goes here - # assertion 2 goes here + assert response.status_code == 404 + assert response_body is None # ---- Complete Assertions Here ---- @@ -113,17 +121,19 @@ def test_delete_goal(client, one_goal): response = client.get("/goals/1") assert response.status_code == 404 -@pytest.mark.skip(reason="test to be completed by student") +#pytest.mark.skip(reason="test to be completed by student") def test_delete_goal_not_found(client): - pass + # Act # ---- Complete Act Here ---- + response = client.delete("/goals/1") + response_body = response.get_json() # Assert # ---- Complete Assertions Here ---- - # assertion 1 goes here - # assertion 2 goes here + assert response.status_code == 404 + assert response_body is None # ---- Complete Assertions Here ---- From f6b28d1273056d3ba2d975c04bfae29328892c1f Mon Sep 17 00:00:00 2001 From: Melinda Date: Thu, 11 Nov 2021 19:29:53 -0800 Subject: [PATCH 10/13] establishing relationship with Goal and Task Models --- app/models/goal.py | 2 ++ app/models/task.py | 1 + app/routes.py | 14 +------------ migrations/versions/2c70c891453e_.py | 30 ++++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 migrations/versions/2c70c891453e_.py diff --git a/app/models/goal.py b/app/models/goal.py index f1dd812ee..ac4babdc9 100644 --- a/app/models/goal.py +++ b/app/models/goal.py @@ -1,10 +1,12 @@ from flask import current_app +from sqlalchemy.orm import backref from app import db class Goal(db.Model): goal_id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) + tasks = db.relationship("Task", backref="goal", lazy=True) def to_dict(self): return{ diff --git a/app/models/task.py b/app/models/task.py index 19a4a1475..272b98fd2 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -11,6 +11,7 @@ class Task(db.Model): title = db.Column(db.String) description = db.Column(db.String) completed_at = db.Column(db.DateTime,nullable=True) + goal_id = db.Column(db.Integer, db.ForeignKey('goal.goal_id'), nullable=True) def to_dict(self): return{ diff --git a/app/routes.py b/app/routes.py index fe1c5aa71..61d8bfa96 100644 --- a/app/routes.py +++ b/app/routes.py @@ -180,19 +180,7 @@ def handle_get_goals(): ) return jsonify(goals_response) -# Wave 5 Get One Goal: Getting One Saved Goal/No Matching Goal -@goals_bp.route("/", methods=["GET"]) -def handle_get_one_goal(goal_id): - # Need to query through the data base - goal = Goal.query.get_or_404(goal_id) - # Need to prepare response to give to client - goal_response = { - "goal": { - "id": goal.goal_id, - "title": goal.title, - } - } - return jsonify(goal_response) + # Wave 5 Update Goal: Update Goal/No Matching Goal @goals_bp.route("/", methods=["PUT"]) diff --git a/migrations/versions/2c70c891453e_.py b/migrations/versions/2c70c891453e_.py new file mode 100644 index 000000000..5953f5b56 --- /dev/null +++ b/migrations/versions/2c70c891453e_.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: 2c70c891453e +Revises: 71cbf284bfc7 +Create Date: 2021-11-11 18:11:45.863522 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '2c70c891453e' +down_revision = '71cbf284bfc7' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('task', sa.Column('goal_id', sa.Integer(), nullable=True)) + op.create_foreign_key(None, 'task', 'goal', ['goal_id'], ['goal_id']) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint(None, 'task', type_='foreignkey') + op.drop_column('task', 'goal_id') + # ### end Alembic commands ### From e448be41e921ec8f7351c3dff0bf6c477cf91037 Mon Sep 17 00:00:00 2001 From: Melinda Date: Sun, 14 Nov 2021 18:04:06 -0800 Subject: [PATCH 11/13] created GET and POST in wave 6 --- app/models/goal.py | 30 ++- app/models/task.py | 20 +- app/routes.py | 193 ++++++++++++++---- migrations/versions/2c70c891453e_.py | 30 --- migrations/versions/71cbf284bfc7_.py | 28 --- .../{daed2d606291_.py => a86f4efc50c0_.py} | 17 +- 6 files changed, 201 insertions(+), 117 deletions(-) delete mode 100644 migrations/versions/2c70c891453e_.py delete mode 100644 migrations/versions/71cbf284bfc7_.py rename migrations/versions/{daed2d606291_.py => a86f4efc50c0_.py} (62%) diff --git a/app/models/goal.py b/app/models/goal.py index ac4babdc9..a873fcf5d 100644 --- a/app/models/goal.py +++ b/app/models/goal.py @@ -4,15 +4,35 @@ class Goal(db.Model): - goal_id = db.Column(db.Integer, primary_key=True) + id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) + # genres = db.relationship("Genre", secondary="books_genres", backref="books") tasks = db.relationship("Task", backref="goal", lazy=True) def to_dict(self): - return{ + if self.list_of_task_ids(): - "goal_id": self.goal_id, - "title": self.title, + return{ - } + "id": self.id, + "title": self.title, + "tasks_ids": self.list_of_task_ids() + } + else: + return{ + "id": self.id, + "title": self.title + } + + def list_of_task_ids(self): + task_ids = [task.id for task in self.tasks] + return task_ids + + def task_list(self): + list = [] + for task in self.tasks: + list.append(task.to_dict) + + return list + diff --git a/app/models/task.py b/app/models/task.py index 272b98fd2..1e2a869bc 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -7,19 +7,29 @@ # completed_at: a datetime that has the date that a task is completed on. Can be nullable, and contain a null value. A task with a null value for completed_at has not been completed. class Task(db.Model): - task_id = db.Column(db.Integer, primary_key=True) + id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String) description = db.Column(db.String) completed_at = db.Column(db.DateTime,nullable=True) - goal_id = db.Column(db.Integer, db.ForeignKey('goal.goal_id'), nullable=True) + goal_id = db.Column(db.Integer, db.ForeignKey('goal.id'), nullable=True) def to_dict(self): - return{ + if self.goal_id is None: + return { + "id": self.id, + "title": self.title, + "description": self.description, + "is_complete": self.check_for_complete_task(), + } + else: + + return{ - "id": self.task_id, + "id": self.id, "title": self.title, "description": self.description, - "is_complete": self.check_for_complete_task() + "is_complete": self.check_for_complete_task(), + "goal_id": self.goal_id } diff --git a/app/routes.py b/app/routes.py index 61d8bfa96..2b0243a9c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -36,7 +36,7 @@ def handle_tasks(): tasks_response.append( { "description": task.description, - "id": task.task_id, + "id": task.id, "is_complete": False if has_complete == None else has_complete, "title": task.title, } @@ -47,10 +47,10 @@ def handle_tasks(): request_body = request.get_json() #Wave 1: Create A Task: Missing Title if "title" not in request_body or "description" not in request_body or "completed_at" not in request_body: - response_body= { + return jsonify ({ "details": "Invalid data" - } - return make_response(response_body, 400) + }), 400 + new_task = Task( title=request_body["title"], @@ -74,7 +74,7 @@ def handle_one_task(task_id): has_complete = task.completed_at task_response={ "task": { - "id": task.task_id, + "id": task.id, "title": task.title, "description": task.description, "is_complete": False if has_complete == None else has_complete, @@ -99,7 +99,7 @@ def handle_one_task(task_id): db.session.delete(task) db.session.commit() response = { - "details": f'Task {task.task_id} "{task.title}" successfully deleted' + "details": f'Task {task.id} "{task.title}" successfully deleted' } json_response = jsonify(response) return make_response(json_response, 200) @@ -146,56 +146,60 @@ def handle_post_goals(): request_body = request.get_json() if "title" not in request_body: - response_body= { + return jsonify ( { "details": "Invalid data" - } - return make_response(response_body, 400) + }), 400 new_goal = Goal( title = request_body["title"] ) db.session.add(new_goal) db.session.commit() - response_body = { - "goal": { - "id": new_goal.goal_id, - "title": new_goal.title - } - } + - return jsonify(response_body), 201 + return jsonify({"goal":new_goal.to_dict()}), 201 # Wave 5 Get Goals: Getting Saved Goals @goals_bp.route("", methods=["GET"]) -def handle_get_goals(): - goals = Goal.query.all() - goals_response = [] - for goal in goals: - goals_response.append( - { +def handle_goals(): + goals = Goal.query.all() + goals_response = [] + for goal in goals: + goals_response.append(goal.to_dict()) + return jsonify(goals_response), 200 +# @goals_bp.route("", methods=["GET"]) +# def handle_get_goals(): +# goals = Goal.query.all() +# goals_response = [] +# for goal in goals: +# goals_response.append(goal.to_dict()) +# # { - "id": goal.goal_id, - "title": goal.title, - } - ) - return jsonify(goals_response) +# # "id": goal.goal_id, +# # "title": goal.title +# # } +# #) +# return jsonify(goals_response), 200 # Wave 5 Update Goal: Update Goal/No Matching Goal -@goals_bp.route("/", methods=["PUT"]) +@goals_bp.route("/", methods=["PUT", "GET"]) def handle_update_one_goal(goal_id): goal = Goal.query.get_or_404(goal_id) - form_data = request.get_json() - if "title" not in form_data: - response_body= { - "details": "title required" - } - return make_response(response_body, 400) - goal.title = form_data["title"] + if request.method == "GET": + return jsonify({"goal":goal.to_dict()}),200 + elif request.method == "PUT": + form_data = request.get_json() + if "title" not in form_data: + return jsonify( { + "details": "title required" + }), 400 + + goal.title = form_data["title"] - db.session.commit() - return jsonify({"goal":goal.to_dict()}),200 + db.session.commit() + return jsonify({"goal":{"goal_id":goal.id, "title":goal.title}}),200 # Wave 5 Deleting A Goal: Deleting A Goal/No Matching Goal @goals_bp.route("/", methods=["DELETE"]) @@ -203,11 +207,116 @@ def handle_delete_one_goal(goal_id): goal = Goal.query.get_or_404(goal_id) db.session.delete(goal) db.session.commit() - response = { - "details": f'Goal {goal.goal_id} "{goal.title}" successfully deleted' - } - json_response = jsonify(response) - return make_response(json_response, 200) + return jsonify( { + "details": f"Goal {goal_id} \"{goal.title}\" successfully deleted" + }),200 + # json_response = jsonify(response) + # return make_response(json_response), 200 + + +@goals_bp.route("//tasks", methods=["POST"]) +def post_task_ids_to_goal(goal_id): + valid_int(goal_id,"goal_id") + request_body = request.get_json() + goal = Goal.query.get_or_404(goal_id) + task_ids = request_body["task_ids"] + for task_id in task_ids: + task = Task.query.get(task_id) + goal.tasks.append(task) + db.session.commit() + return jsonify({"id":goal.id, "task_ids": [task.id for task in goal.tasks]}),200 + +@goals_bp.route("//tasks", methods=["GET"]) +def get_tasks_for_goal(goal_id): + valid_int(goal_id,"goal_id") + goal = Goal.query.get_or_404(goal_id) + response_body = {"id":goal.id, + "title":goal.title, + "tasks":goal.task_list() + } + print(response_body) + return jsonify(response_body),200 + + + + + + + + + + + + + + + + +# def handle_goals_tasks(goal_id): +# valid_int(goal_id,"goal_id") +# goal = Goal.query.get_or_404(goal_id) +# # if request.method == "POST": +# request_body = request.get_json() + +# if "task_ids" not in request_body: +# return jsonify( { +# "details": "task_ids required" +# }), 400 + +# # tasks_with_relations = [] +# task_ids = request_body["task_ids"] +# for task_id in task_ids: + + +# # tasks_with_relations.append(task_id) +# task = Task.query.get(task_id) + +# if task == None: +# # TODO: change this back to correct response +# return jsonify ({"details": "there is no tasks"}), 400 +# goal.tasks.append(task) +# # task.goal_id = goal.goal_id + +# db.session.commit() +# return jsonify({"id":goal.id, "task_ids":[task.id for task in goal.tasks]}), 200 + +# # response_body= { +# # "id": goal.goal_id, +# # "task_ids": tasks_with_relations + +# # } + +# # return (response_body), 200 +# @goals_bp.route("//tasks", methods=["GET"]) +# def get_tasks_for_goal(goal_id): + +# goal = Goal.query.get(goal_id) +# # task_with_relationship_goals = goal.tasks +# # task_list = [] +# # if task_with_relationship_goals: + +# # for thing in task_with_relationship_goals: +# # task_object = {} +# # value_if_true if condition else value_if_false +# # completed = '' if thing.is_complete == '' else thing.is_complete +# # task_object["id"]= thing.task_id +# # task_object["goal_id"]=goal_id +# # task_object["title"]=thing.title +# # task_object["description"]=thing.description +# # # task_object["is_complete"]=completed +# # task_list.append(task_object) + + +# response_body = { +# "id": goal_id, +# "title": goal.title, +# "tasks": goal.task_list() +# } + +# return jsonify(response_body), 200 + + + diff --git a/migrations/versions/2c70c891453e_.py b/migrations/versions/2c70c891453e_.py deleted file mode 100644 index 5953f5b56..000000000 --- a/migrations/versions/2c70c891453e_.py +++ /dev/null @@ -1,30 +0,0 @@ -"""empty message - -Revision ID: 2c70c891453e -Revises: 71cbf284bfc7 -Create Date: 2021-11-11 18:11:45.863522 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '2c70c891453e' -down_revision = '71cbf284bfc7' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('task', sa.Column('goal_id', sa.Integer(), nullable=True)) - op.create_foreign_key(None, 'task', 'goal', ['goal_id'], ['goal_id']) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_constraint(None, 'task', type_='foreignkey') - op.drop_column('task', 'goal_id') - # ### end Alembic commands ### diff --git a/migrations/versions/71cbf284bfc7_.py b/migrations/versions/71cbf284bfc7_.py deleted file mode 100644 index 9d6087113..000000000 --- a/migrations/versions/71cbf284bfc7_.py +++ /dev/null @@ -1,28 +0,0 @@ -"""empty message - -Revision ID: 71cbf284bfc7 -Revises: daed2d606291 -Create Date: 2021-11-08 17:24:12.393653 - -""" -from alembic import op -import sqlalchemy as sa - - -# revision identifiers, used by Alembic. -revision = '71cbf284bfc7' -down_revision = 'daed2d606291' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.add_column('goal', sa.Column('title', sa.String(), nullable=True)) - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_column('goal', 'title') - # ### end Alembic commands ### diff --git a/migrations/versions/daed2d606291_.py b/migrations/versions/a86f4efc50c0_.py similarity index 62% rename from migrations/versions/daed2d606291_.py rename to migrations/versions/a86f4efc50c0_.py index 555080bd5..3a5c55fae 100644 --- a/migrations/versions/daed2d606291_.py +++ b/migrations/versions/a86f4efc50c0_.py @@ -1,8 +1,8 @@ """empty message -Revision ID: daed2d606291 +Revision ID: a86f4efc50c0 Revises: -Create Date: 2021-11-02 11:00:20.230195 +Create Date: 2021-11-14 17:05:52.542184 """ from alembic import op @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. -revision = 'daed2d606291' +revision = 'a86f4efc50c0' down_revision = None branch_labels = None depends_on = None @@ -19,15 +19,18 @@ def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.create_table('goal', - sa.Column('goal_id', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('goal_id') + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') ) op.create_table('task', - sa.Column('task_id', sa.Integer(), nullable=False), + sa.Column('id', sa.Integer(), nullable=False), sa.Column('title', sa.String(), nullable=True), sa.Column('description', sa.String(), nullable=True), sa.Column('completed_at', sa.DateTime(), nullable=True), - sa.PrimaryKeyConstraint('task_id') + sa.Column('goal_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['goal_id'], ['goal.id'], ), + sa.PrimaryKeyConstraint('id') ) # ### end Alembic commands ### From 4c64f58cfeea869bf6aa15f59e8c0061b83f174e Mon Sep 17 00:00:00 2001 From: Melinda Date: Mon, 15 Nov 2021 19:25:24 -0800 Subject: [PATCH 12/13] passed all tests --- app/routes.py | 117 +++++++++++++------------------------------------- 1 file changed, 30 insertions(+), 87 deletions(-) diff --git a/app/routes.py b/app/routes.py index 2b0243a9c..a0ca6904c 100644 --- a/app/routes.py +++ b/app/routes.py @@ -72,15 +72,27 @@ def handle_one_task(task_id): # Wave 1: Get One Task: One Saved Task if request.method == "GET": has_complete = task.completed_at - task_response={ - "task": { - "id": task.id, - "title": task.title, - "description": task.description, - "is_complete": False if has_complete == None else has_complete, - - } - } + if task.goal_id: + task_response={ + "task": { + "id": task.id, + "goal_id": task.goal_id, + "title": task.title, + "description": task.description, + "is_complete": False if has_complete == None else has_complete, + + } + } + else: + task_response={ + "task": { + "id": task.id, + "title": task.title, + "description": task.description, + "is_complete": False if has_complete == None else has_complete, + + } + } return jsonify(task_response) #Wave 1: Update Task, #Wave 1 Update Task: No Matching Task, Update Task 200 OK @@ -167,20 +179,6 @@ def handle_goals(): for goal in goals: goals_response.append(goal.to_dict()) return jsonify(goals_response), 200 -# @goals_bp.route("", methods=["GET"]) -# def handle_get_goals(): -# goals = Goal.query.all() -# goals_response = [] -# for goal in goals: -# goals_response.append(goal.to_dict()) -# # { - -# # "id": goal.goal_id, -# # "title": goal.title -# # } -# #) -# return jsonify(goals_response), 200 - # Wave 5 Update Goal: Update Goal/No Matching Goal @@ -213,7 +211,7 @@ def handle_delete_one_goal(goal_id): # json_response = jsonify(response) # return make_response(json_response), 200 - +#Wave # 6 @goals_bp.route("//tasks", methods=["POST"]) def post_task_ids_to_goal(goal_id): valid_int(goal_id,"goal_id") @@ -230,13 +228,18 @@ def post_task_ids_to_goal(goal_id): def get_tasks_for_goal(goal_id): valid_int(goal_id,"goal_id") goal = Goal.query.get_or_404(goal_id) + + tasks = goal.tasks + tasks_list = [] + for task in tasks: + tasks_list.append(task.to_dict()) response_body = {"id":goal.id, "title":goal.title, - "tasks":goal.task_list() + "tasks": tasks_list } - print(response_body) - return jsonify(response_body),200 + + return jsonify(response_body),200 @@ -252,68 +255,8 @@ def get_tasks_for_goal(goal_id): -# def handle_goals_tasks(goal_id): -# valid_int(goal_id,"goal_id") -# goal = Goal.query.get_or_404(goal_id) -# # if request.method == "POST": -# request_body = request.get_json() -# if "task_ids" not in request_body: -# return jsonify( { -# "details": "task_ids required" -# }), 400 - -# # tasks_with_relations = [] -# task_ids = request_body["task_ids"] -# for task_id in task_ids: - -# # tasks_with_relations.append(task_id) -# task = Task.query.get(task_id) - -# if task == None: -# # TODO: change this back to correct response -# return jsonify ({"details": "there is no tasks"}), 400 -# goal.tasks.append(task) -# # task.goal_id = goal.goal_id - -# db.session.commit() -# return jsonify({"id":goal.id, "task_ids":[task.id for task in goal.tasks]}), 200 - -# # response_body= { -# # "id": goal.goal_id, -# # "task_ids": tasks_with_relations - -# # } - -# # return (response_body), 200 -# @goals_bp.route("//tasks", methods=["GET"]) -# def get_tasks_for_goal(goal_id): - -# goal = Goal.query.get(goal_id) -# # task_with_relationship_goals = goal.tasks -# # task_list = [] -# # if task_with_relationship_goals: - -# # for thing in task_with_relationship_goals: -# # task_object = {} -# # value_if_true if condition else value_if_false -# # completed = '' if thing.is_complete == '' else thing.is_complete -# # task_object["id"]= thing.task_id -# # task_object["goal_id"]=goal_id -# # task_object["title"]=thing.title -# # task_object["description"]=thing.description -# # # task_object["is_complete"]=completed -# # task_list.append(task_object) - - -# response_body = { -# "id": goal_id, -# "title": goal.title, -# "tasks": goal.task_list() -# } - -# return jsonify(response_body), 200 From ce94904b3c88253c9cb8b21e1f07ccbea3d461f5 Mon Sep 17 00:00:00 2001 From: Melinda Date: Mon, 15 Nov 2021 21:15:18 -0800 Subject: [PATCH 13/13] added Procfile --- Procfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..62e430aca --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn 'app:create_app()' \ No newline at end of file