Skip to content

Crow-BCaprirolo-Task-List-API#28

Open
sausagehands wants to merge 10 commits intoAda-C24:mainfrom
sausagehands:main
Open

Crow-BCaprirolo-Task-List-API#28
sausagehands wants to merge 10 commits intoAda-C24:mainfrom
sausagehands:main

Conversation

@sausagehands
Copy link
Copy Markdown

No description provided.

Copilot AI review requested due to automatic review settings December 21, 2025 20:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive Task List API with Goal management functionality. The implementation includes full CRUD operations for both Tasks and Goals, establishes a one-to-many relationship between Goals and Tasks, and adds CORS support for cross-origin requests.

  • Implements Task and Goal models with SQLAlchemy relationships
  • Creates RESTful API endpoints for task and goal management including creation, retrieval, updates, and deletion
  • Adds support for marking tasks as complete/incomplete with Slack notifications
  • Enables test suite by uncommenting all skipped tests and completing incomplete test implementations

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
app/init.py Initializes Flask app with CORS support and registers task/goal blueprints
app/models/task.py Defines Task model with goal relationship and serialization methods
app/models/goal.py Defines Goal model with tasks relationship and serialization methods
app/routes/task_routes.py Implements RESTful endpoints for task CRUD operations
app/routes/goal_routes.py Implements RESTful endpoints for goal CRUD operations and task associations
app/routes/route_utilities.py Provides shared utility functions for validation, CRUD operations, and Slack notifications
migrations/versions/*.py Database migration files creating tables and relationships
seed.py Database seeding script with sample goals and tasks
requirements.txt Adds flask-cors dependency
tests/test_wave_01.py Uncomments and completes basic task functionality tests
tests/test_wave_02.py Uncomments task sorting tests
tests/test_wave_03.py Uncomments and completes task completion/incompletion tests
tests/test_wave_05.py Uncomments and completes goal functionality tests
tests/test_wave_06.py Uncomments and completes goal-task relationship tests
tests/test_wave_07.py Uncomments and completes route utility tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/routes/goal_routes.py
def get_tasks_by_goal(goal_id):
goal = validate_model(Goal, goal_id)

return{
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space between 'return' and the opening brace. Should be 'return {' for consistency with the rest of the codebase.

Suggested change
return{
return {

Copilot uses AI. Check for mistakes.
Comment thread app/routes/goal_routes.py
for task in goal.tasks:
task.goal_id = None

#add new tasks
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is missing a space after the hash symbol. Should be '# add new tasks' for consistency with Python style guidelines.

Suggested change
#add new tasks
# add new tasks

Copilot uses AI. Check for mistakes.
Comment thread app/models/goal.py
Comment on lines +22 to +25
def from_dict(cls, task_data):
new_task = cls(title=task_data['title'])

return new_task
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent naming: the parameter is named 'task_data' but this method creates a Goal object. It should be renamed to 'goal_data' for clarity.

Suggested change
def from_dict(cls, task_data):
new_task = cls(title=task_data['title'])
return new_task
def from_dict(cls, goal_data):
new_goal = cls(title=goal_data['title'])
return new_goal

Copilot uses AI. Check for mistakes.
Comment thread app/models/goal.py
Comment on lines +22 to +25
def from_dict(cls, task_data):
new_task = cls(title=task_data['title'])

return new_task
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent naming: the variable is named 'new_task' but it's actually a Goal object. It should be renamed to 'new_goal' for clarity.

Suggested change
def from_dict(cls, task_data):
new_task = cls(title=task_data['title'])
return new_task
def from_dict(cls, goal_data):
new_goal = cls(title=goal_data['title'])
return new_goal

Copilot uses AI. Check for mistakes.
Comment thread tests/test_wave_05.py
@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
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'pass' statement on line 110 is unnecessary and should be removed since the function body has actual implementation below it.

Suggested change
pass

Copilot uses AI. Check for mistakes.
Comment thread tests/test_wave_05.py
"id": 1,
"title": "Updated Goal Title"
}
assert response_body["title"] == "Updated Goal Title"
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant assertion. Line 149 asserts response_body["title"] == "Updated Goal Title" which is already verified by the full dictionary comparison on lines 145-148.

Suggested change
assert response_body["title"] == "Updated Goal Title"

Copilot uses AI. Check for mistakes.
Comment thread app/models/task.py

return task_as_dict

#creates a task from a dictionary
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is missing a space after the hash symbol. Should be '# creates a task from a dictionary' for consistency with Python style guidelines.

Copilot uses AI. Check for mistakes.
Comment thread app/models/task.py
task_as_dict["goal_id"] = self.goal_id

if self.completed_at:
task_as_dict["completed_at"]= self.completed_at.isoformat()
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after the equals sign. Should be 'task_as_dict["completed_at"] = self.completed_at.isoformat()' for consistent spacing with PEP 8 style guidelines.

Suggested change
task_as_dict["completed_at"]= self.completed_at.isoformat()
task_as_dict["completed_at"] = self.completed_at.isoformat()

Copilot uses AI. Check for mistakes.
Comment thread app/routes/goal_routes.py
Comment on lines +5 to +6
from .route_utilities import *

Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import pollutes the enclosing namespace, as the imported module app.routes.route_utilities does not define 'all'.

Suggested change
from .route_utilities import *
from .route_utilities import (
validate_model,
db,
create_model,
get_all_items,
get_one_item,
update_entire_item,
update_partial_item,
mark_item_complete,
mark_item_incomplete,
delete_item,
)

Copilot uses AI. Check for mistakes.
Comment thread app/routes/task_routes.py
Comment on lines +1 to +3
from flask import Blueprint
from app.models.task import Task
from .route_utilities import *
Copy link

Copilot AI Dec 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import pollutes the enclosing namespace, as the imported module app.routes.route_utilities does not define 'all'.

Suggested change
from flask import Blueprint
from app.models.task import Task
from .route_utilities import *
from flask import Blueprint, request, Response
from app.models.task import Task
from .route_utilities import (
create_model,
get_all_items,
get_one_item,
update_entire_item,
update_partial_item,
mark_item_complete,
mark_item_incomplete,
delete_item,
)

Copilot uses AI. Check for mistakes.
@Ada-C24 Ada-C24 deleted a comment from Copilot AI Dec 31, 2025
@Ada-C24 Ada-C24 deleted a comment from Copilot AI Dec 31, 2025
@Ada-C24 Ada-C24 deleted a comment from Copilot AI Dec 31, 2025
@Ada-C24 Ada-C24 deleted a comment from Copilot AI Dec 31, 2025
Copy link
Copy Markdown

@apradoada apradoada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GREEN

Great job, Bianca!

Overall, your models look good, your routes are solid and your helper functions are well written.

I think my biggest piece of advice here would be to take your helper functions and see if there are ways for you to make them more generic. Right now, they work for the two model system that you have and the attributes that exist for each model, but they start to fall apart as you add more models. If you want to revisit this project, I think that would be a great place to start!

If you have any questions, don't hesitate to reach out!

Comment thread app/models/goal.py
Comment on lines +5 to 7
if TYPE_CHECKING:
from .task import Task

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While TYPE_CHECKING isn't necessarily required here because we have a one-to-many relationship, it is best practice and is necessary to avoid circular imports in a many-to-many relationship, so great job using it here.

Also, as stated in our Learn lessons, it does allow us to get rid of the yellow underline on line 11!

Comment thread app/models/goal.py
def from_dict(cls, task_data):
new_task = cls(title=task_data['title'])

return new_task
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are currently in the Goal model but refer to task_data here. It would appear you copied and pasted from the Task model which is perfectly fine, but do make sure to make the appropriate changes!

Comment thread app/models/task.py
Comment on lines +22 to +26
task_as_dict = {}
task_as_dict["id"]= self.id
task_as_dict["title"]= self.title
task_as_dict["description"]= self.description
task_as_dict["is_complete"]= self.completed_at is not None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a nice start, but it does start to get a little clunky. Feel free to favor building a dictionary directly:

Suggested change
task_as_dict = {}
task_as_dict["id"]= self.id
task_as_dict["title"]= self.title
task_as_dict["description"]= self.description
task_as_dict["is_complete"]= self.completed_at is not None
task_as_dict = {
"id": self.id
"title": self.title
"description": self.description
"is_complete": self.completed_at is not None
}

Comment thread app/models/task.py
Comment on lines +33 to +34
else:
None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else statement currently does not do anything, so it can be removed completely.

Comment thread app/routes/goal_routes.py
db.session.add(new_task)
db.session.commit

return new_task.to_dict(), 200
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flask returns status code 200 by default so we don't need to explicitly return it! We can go ahead and just return the new task's dictionary.

Comment on lines +81 to +90
def update_entire_item(cls, id, goal_update=False):
item = validate_model(cls, id)
request_body = request.get_json()

item.title = request_body["title"]
if not goal_update:
item.description = request_body["description"]
db.session.commit()

return item
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I'm consistently impressed by how your brain works with these types of problems. I was initially unsure of how this particular helper function would work, but you made it pretty flexible.

That being said, if we were to add more and more models, this would become less stable and would need to be tweaked in order to make sure it can apply to more models.

Comment on lines +96 to +106
if 'title' in request_body:
item.title = request_body['title']

if 'description' in request_body:
item.description = request_body['description']

if 'is_complete' in request_body:
if request_body['is_complete']:
item.completed_at = datetime.now()
else:
item.completed_at = None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The small issue I see here again is its scalability. If we had more models with different attributes, then we'll have to add more if statements which isn't entirely feasible. In its current form, it also lends itself to the issue of trying to access attributes that don't exist to different models.

Comment on lines +112 to +138
def mark_item_complete(cls, id):
item = validate_model(cls, id)

item.completed_at = datetime.now()

db.session.commit()

send_slack_notification(item.title)

return Response(status=204, mimetype="application/json")

def mark_item_incomplete(cls, id):
item = validate_model(cls, id)

item.completed_at = None

db.session.commit()

return Response(status=204, mimetype="application/json")

def delete_item(cls, id):
item = validate_model(cls, id)

db.session.delete(item)
db.session.commit()

return Response(status=204, mimetype="application/json") No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three look great!

Comment thread app/routes/task_routes.py
Comment on lines +41 to +44




No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra whitespace! We can get rid of this!

Comment thread app/__init__.py
Comment on lines +5 to +6
from .routes.task_routes import bp as tasks_bp
from .routes.goal_routes import bp as goals_bp
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job aliasing your blueprints!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants