-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sharks-Xiomara R. #93
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,102 @@ | ||||||
from flask import Blueprint, jsonify, make_response, request | ||||||
from requests import session | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This
Suggested change
|
||||||
from app.helpers import validate_goal, validate_task | ||||||
from app.models.goal import Goal | ||||||
from app import db | ||||||
from app.models.task import Task | ||||||
|
||||||
|
||||||
goal_bp = Blueprint("goal", __name__, url_prefix="/goals") | ||||||
|
||||||
# Create goal | ||||||
|
||||||
|
||||||
@goal_bp.route("", methods=["POST"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
def create_goal(): | ||||||
request_body = request.get_json() | ||||||
|
||||||
if "title" not in request_body: | ||||||
return { | ||||||
"details": "Invalid data" | ||||||
}, 400 | ||||||
|
||||||
new_goal = Goal.create(request_body) | ||||||
|
||||||
db.session.add(new_goal) | ||||||
db.session.commit() | ||||||
|
||||||
return make_response(jsonify({"goal": new_goal.to_json()}), 201) | ||||||
|
||||||
# Get all goals | ||||||
|
||||||
|
||||||
@goal_bp.route("", methods=["GET"]) | ||||||
def get_all_goals(): | ||||||
title_query = request.args.get("sort") | ||||||
|
||||||
if title_query == "asc": | ||||||
goals = Goal.query.order_by(Goal.title.asc()) | ||||||
elif title_query == "desc": | ||||||
goals = Goal.query.order_by(Goal.title.desc()) | ||||||
else: | ||||||
goals = Goal.query.all() | ||||||
|
||||||
goals_response = [] | ||||||
|
||||||
for goal in goals: | ||||||
goals_response.append(goal.to_json()) | ||||||
|
||||||
return jsonify(goals_response), 200 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try to stay consistent with your return statements here. Most of them are using
Suggested change
|
||||||
|
||||||
# Get one goal | ||||||
|
||||||
|
||||||
@goal_bp.route("/<id>", methods=["GET"]) | ||||||
def get_one_goal(id): | ||||||
goal = validate_goal(id) | ||||||
return jsonify({"goal": goal.to_json()}), 200 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
# Update goal | ||||||
|
||||||
|
||||||
@goal_bp.route("/<id>", methods=["PUT"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
def update_goal(id): | ||||||
goal = validate_goal(id) | ||||||
request_body = request.get_json() | ||||||
|
||||||
goal.update(request_body) | ||||||
db.session.commit() | ||||||
|
||||||
return make_response(jsonify({"goal": goal.to_json()})), 200 | ||||||
|
||||||
|
||||||
# Delete goal | ||||||
@goal_bp.route("/<id>", methods=["DELETE"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
def delete_goal(id): | ||||||
goal = validate_goal(id) | ||||||
db.session.delete(goal) | ||||||
db.session.commit() | ||||||
|
||||||
return make_response(jsonify({"details": f"Goal {id} \"{goal.title}\" successfully deleted"}), 200) | ||||||
|
||||||
# Sending a List of Task IDs to a Goal | ||||||
|
||||||
|
||||||
@goal_bp.route("/<id>/tasks", methods=["POST"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
def add_tasks_to_one_goal(id): | ||||||
goal = validate_goal(id) | ||||||
request_body = request.get_json() | ||||||
|
||||||
for id in request_body["id"]: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is where I think the last wave is failing. Double check what the correct key is in the tests! |
||||||
new_task = Task.query.get(id) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I bet we could use the
Suggested change
|
||||||
new_task.id = id | ||||||
db.session.commit() | ||||||
|
||||||
list_of_task_ids = [] | ||||||
for task in goal.tasks: | ||||||
list_of_task_ids.append(task.id) | ||||||
|
||||||
return make_response(jsonify({"id": {new_task.id}, "task_ids": list_of_task_ids})), 200 | ||||||
|
||||||
|
||||||
# @goal_bp.route("/<goal_id>/tasks", methods=["POST"]) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from flask import make_response, abort | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great job separating out helper functions! |
||
from app.models.task import Task | ||
from app.models.goal import Goal | ||
|
||
|
||
def validate_task(id): | ||
try: | ||
id = int(id) | ||
except: | ||
return abort(make_response({"details": f"Task is invalid"}, 400)) | ||
|
||
task = Task.query.get(id) | ||
|
||
if not task: | ||
abort(make_response({"details": f"Task 1 not found"}, 404)) | ||
|
||
return task | ||
|
||
|
||
def validate_goal(id): | ||
try: | ||
id = int(id) | ||
except: | ||
abort(make_response({"details": f"Goal is invalid"}, 400)) | ||
|
||
goal = Goal.query.get(id) | ||
|
||
if not goal: | ||
abort(make_response({"details": f"Goal 1 not found"}, 404)) | ||
return goal |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,25 @@ | ||
|
||
from app import db | ||
|
||
|
||
class Goal(db.Model): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
goal_id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String, nullable=False) | ||
tasks = db.relationship("Task", back_populates="goals", lazy=True) | ||
|
||
def to_json(self): | ||
return { | ||
"id": self.id, | ||
"title": self.title | ||
} | ||
|
||
def update(self, request_body): | ||
self.title = request_body["title"] | ||
|
||
@classmethod | ||
def create(cls, request_body): | ||
new_task = cls( | ||
title=request_body["title"] | ||
) | ||
|
||
return new_task |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,46 @@ | ||||||
|
||||||
from email.policy import default | ||||||
from unittest.mock import DEFAULT | ||||||
Comment on lines
+2
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm where did these come from? Double check where your default attribute comes from in SQLAlchemy. It is part of the
Suggested change
|
||||||
from app import db | ||||||
from .goal import Goal | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to import the other model here since we aren't creating an instances of Goal inside Task; we refer to "Goal" as a string, not an actual instance of the model.
Suggested change
|
||||||
from sqlalchemy.orm import relationship | ||||||
|
||||||
# DEFINING A MODEL | ||||||
''' | ||||||
Models in our Flask code will create a | ||||||
direct connection between the data modeled in our | ||||||
database. We will create a class for each model. | ||||||
The class will define the state and behavior of our model. | ||||||
''' | ||||||
|
||||||
|
||||||
class Task(db.Model): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||||
task_id = db.Column(db.Integer, primary_key=True) | ||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||||||
title = db.Column(db.String) | ||||||
description = db.Column(db.String) | ||||||
completed_at = db.Column(db.DateTime, default=None) | ||||||
goal_id = db.Column(db.Integer, db.ForeignKey("goal.id"), nullable=True) | ||||||
goals = db.relationship("Goal", back_populates="tasks") | ||||||
|
||||||
def to_json(self): | ||||||
return { | ||||||
"id": self.id, | ||||||
"title": self.title, | ||||||
"description": self.description, | ||||||
"is_complete": False if not self.completed_at else True | ||||||
} | ||||||
|
||||||
def update(self, request_body): | ||||||
self.title = request_body["title"] | ||||||
self.description = request_body["description"] | ||||||
# self.completed_at = request_body["completed_at"] | ||||||
|
||||||
@classmethod | ||||||
def create(cls, request_body): | ||||||
new_task = cls( | ||||||
title=request_body['title'], | ||||||
description=request_body['description'], | ||||||
completed_at=request_body.get("completed_at", None) | ||||||
) | ||||||
|
||||||
return new_task |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -1 +1,135 @@ | ||||
from flask import Blueprint | ||||
from flask import Blueprint, jsonify, abort, make_response, request | ||||
from requests import session | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
from .helpers import validate_task | ||||
from app import db | ||||
from .models.task import Task | ||||
from datetime import datetime | ||||
import requests | ||||
import os | ||||
|
||||
|
||||
# TASK BLUEPRINT | ||||
''' | ||||
Blueprints are a Flask class that provides a pattern | ||||
for grouping related routes (endpoints) | ||||
''' | ||||
|
||||
task_bp = Blueprint("task", __name__, url_prefix="/tasks") | ||||
|
||||
|
||||
# Create a Task: Valid Task With null completed_at | ||||
|
||||
@task_bp.route("", methods=["POST"]) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||
def create_task(): | ||||
request_body = request.get_json() | ||||
|
||||
if "title" not in request_body: | ||||
return { | ||||
"details": "Invalid data" | ||||
}, 400 | ||||
if "description" not in request_body: | ||||
return { | ||||
"details": "Invalid data" | ||||
}, 400 | ||||
|
||||
new_task = Task.create(request_body) | ||||
|
||||
db.session.add(new_task) | ||||
db.session.commit() | ||||
|
||||
return make_response(jsonify({"task": new_task.to_json()}), 201) | ||||
|
||||
|
||||
# Get Tasks | ||||
|
||||
@task_bp.route("", methods=["POST", "GET"]) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||
def get_all_tasks(): | ||||
title_query = request.args.get("sort") | ||||
|
||||
# description_query=request.args.get("description") | ||||
|
||||
if title_query == "asc": | ||||
tasks = Task.query.order_by(Task.title.asc()) | ||||
elif title_query == "desc": | ||||
tasks = Task.query.order_by(Task.title.desc()) | ||||
else: | ||||
tasks = Task.query.all() | ||||
|
||||
# tasks_response = [task.to_dict() for task in tasks] | ||||
|
||||
tasks_response = [] | ||||
|
||||
for task in tasks: | ||||
tasks_response.append(task.to_json()) | ||||
|
||||
return jsonify(tasks_response), 200 | ||||
|
||||
|
||||
# Get One Task: One Saved Task | ||||
@task_bp.route("/<id>", methods=["GET"]) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||
def get_one_task(id): | ||||
task = validate_task(id) | ||||
return jsonify({"task": task.to_json()}), 200 | ||||
|
||||
|
||||
# Update Task | ||||
@task_bp.route("/<id>", methods=["PUT"]) | ||||
def update_task(id): | ||||
task = validate_task(id) | ||||
request_body = request.get_json() | ||||
|
||||
task.update(request_body) | ||||
db.session.commit() | ||||
|
||||
return make_response(jsonify({"task": task.to_json()}), 200) | ||||
|
||||
|
||||
# Delete Task: Deleting a Task | ||||
@task_bp.route("/<id>", methods=["DELETE"]) | ||||
def delete_task(id): | ||||
task = validate_task(id) | ||||
db.session.delete(task) | ||||
db.session.commit() | ||||
|
||||
return make_response(jsonify({"details": f"Task {id} \"{task.title}\" successfully deleted"})) | ||||
|
||||
# Mark Complete | ||||
|
||||
|
||||
@task_bp.route("/<id>/mark_complete", methods=["PATCH"]) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||
def mark_complete(id): | ||||
task = validate_task(id) | ||||
|
||||
task.completed_at = datetime.utcnow() | ||||
|
||||
db.session.commit() | ||||
post_message_to_slack(task) | ||||
|
||||
return make_response(jsonify({"task": task.to_json()})), 200 | ||||
|
||||
# Slack | ||||
|
||||
|
||||
def post_message_to_slack(task): | ||||
send_msg_path = "https://slack.com/api/chat.postMessage" | ||||
confirm_message = f"You completed the task {task.title}!" | ||||
query_params = { | ||||
"channel": "task-notifications", | ||||
"text": confirm_message | ||||
} | ||||
headers = { | ||||
"Authorization": os.environ.get("slack_token") | ||||
} | ||||
requests.post(send_msg_path, params=query_params, headers=headers) | ||||
Comment on lines
+113
to
+123
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's move this to the |
||||
|
||||
|
||||
# Mark Incomplete | ||||
@task_bp.route("/<id>/mark_incomplete", methods=["PATCH"]) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||||
def mark_incomplete(id): | ||||
task = validate_task(id) | ||||
|
||||
task.completed_at = None | ||||
|
||||
db.session.commit() | ||||
|
||||
return make_response(jsonify({"task": task.to_json()})), 200 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Single-database configuration for Flask. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 great job separating these routes out into two different files! This is a common practice and makes it easier for teams to work on a project together without accidentally stepping on each other's toes.