-
Notifications
You must be signed in to change notification settings - Fork 128
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
Kunzite - Erina P. #124
base: main
Are you sure you want to change the base?
Kunzite - Erina P. #124
Changes from all commits
6d442ac
b2301c9
2297f92
02185f6
d8636c8
1376a89
cd9d208
33971c6
02204b7
6be68e7
bd82091
83ce76b
c1459ce
ba96899
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 |
---|---|---|
@@ -1,5 +1,30 @@ | ||
from app import db | ||
|
||
from datetime import datetime | ||
|
||
class Task(db.Model): | ||
task_id = db.Column(db.Integer, primary_key=True) | ||
task_id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
title = db.Column(db.String, nullable=False) | ||
description = db.Column(db.String, nullable=False) | ||
completed_at = db.Column(db.DateTime, nullable=True) | ||
goal = db.relationship("Goal", back_populates="tasks") | ||
goal_id = db.Column(db.Integer, db.ForeignKey('goal.goal_id'), nullable=True) | ||
|
||
def to_dict(self): | ||
task_dict = {} | ||
task_dict["id"] = self.task_id | ||
task_dict["title"] = self.title | ||
task_dict["description"] = self.description | ||
task_dict["is_complete"] = self.completed_at != None | ||
|
||
if self.goal_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. Nice! |
||
task_dict["goal_id"] = self.goal_id | ||
|
||
return task_dict | ||
|
||
@classmethod | ||
def from_dict(cls, task_dict): | ||
return cls( | ||
title=task_dict["title"], | ||
description=task_dict["description"], | ||
completed_at=task_dict.get("completed_at") | ||
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. Good approach, setting |
||
) |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
from app import db | ||
from app.models.goal import Goal | ||
from app.models.task import Task | ||
from flask import Blueprint, request, jsonify, make_response, abort | ||
|
||
goals_bp = Blueprint("goals_bp", __name__, url_prefix="/goals") | ||
|
||
|
||
def validate_model(cls, model_id): | ||
try: | ||
model_id = int(model_id) | ||
except: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} invalid"}, 400)) | ||
|
||
model = cls.query.get(model_id) | ||
|
||
if not model: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} not found"}, 404)) | ||
|
||
return model | ||
|
||
|
||
@goals_bp.route("", methods=["POST"]) | ||
def create_goal(): | ||
request_body = request.get_json() | ||
|
||
try: | ||
new_goal = Goal.from_dict(request_body) | ||
except KeyError as err: | ||
abort(make_response({"details": "Invalid data"}, 400)) | ||
|
||
db.session.add(new_goal) | ||
db.session.commit() | ||
|
||
goal_dict = {} | ||
goal_dict["goal"] = new_goal.to_dict() | ||
|
||
return jsonify(goal_dict), 201 | ||
|
||
|
||
@goals_bp.route("", methods=["GET"]) | ||
def sort_by_title(): | ||
sort_query = request.args.get("sort") | ||
if sort_query == "asc": | ||
goals = Goal.query.order_by(Goal.title) | ||
elif sort_query == "desc": | ||
goals = Goal.query.order_by(Goal.title.desc()) | ||
else: | ||
goals = Goal.query.all() | ||
|
||
goal_response = [goal.to_dict() for goal in goals] | ||
|
||
return jsonify(goal_response) | ||
|
||
|
||
@goals_bp.route("/<goal_id>", methods=["GET"]) | ||
def get_one_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
goal_dict = {"goal": goal.to_dict()} | ||
|
||
return jsonify(goal_dict) | ||
|
||
|
||
@goals_bp.route("/<goal_id>", methods=["PUT"]) | ||
def update_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
|
||
request_body = request.get_json() | ||
goal.title = request_body["title"] | ||
|
||
db.session.commit() | ||
|
||
goal_dict = {"goal": goal.to_dict()} | ||
|
||
return jsonify(goal_dict) | ||
|
||
|
||
@goals_bp.route("/<goal_id>", methods=["DELETE"]) | ||
def delete_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
|
||
db.session.delete(goal) | ||
db.session.commit() | ||
|
||
goal_message = {"details": f'Goal {goal.goal_id} \"{goal.title}\" successfully deleted'} | ||
|
||
return jsonify(goal_message) | ||
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 like how you've been using the fact that Flask's response default HTTP status code is 200 and therefore omitting it from the |
||
|
||
|
||
@goals_bp.route("/<goal_id>/tasks", methods=["GET"]) | ||
def get_all_tasks_for_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
goal_response = goal.to_dict(tasks=True) | ||
return make_response(goal_response), 200 | ||
|
||
|
||
@goals_bp.route("/<goal_id>/tasks", methods=["POST"]) | ||
def post_tasks_to_goal(goal_id): | ||
goal = validate_model(Goal, goal_id) | ||
request_body = request.get_json() | ||
task_ids = request_body["task_ids"] | ||
|
||
for task in goal.tasks: | ||
task.goal_id = None | ||
|
||
|
||
for task_id in task_ids: | ||
task = validate_model(Task, task_id) | ||
task.goal_id = goal.goal_id | ||
|
||
goal.title = request.args.get("title", goal.title) | ||
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 it appears that you're making it possible to send a request with a |
||
|
||
db.session.commit() | ||
|
||
return make_response({"id": goal.goal_id, "task_ids": task_ids}, 200) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
from flask import Blueprint, request, jsonify, make_response, abort | ||
from app import db | ||
from app.models.task import Task | ||
from datetime import datetime | ||
from sqlalchemy.types import DateTime | ||
from sqlalchemy.sql.functions import now | ||
import requests, os | ||
|
||
tasks_bp = Blueprint("tasks_bp", __name__, url_prefix="/tasks") | ||
|
||
def validate_model(cls, model_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's a good opportunity for some refactoring! Since you're defining the same function in two route files, you could create a new file 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 wanted to do this with a little more time! I think I'll go back and add it! |
||
try: | ||
model_id = int(model_id) | ||
except: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} invalid"}, 400)) | ||
|
||
model = cls.query.get(model_id) | ||
|
||
if not model: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} not found"}, 404)) | ||
|
||
return model | ||
|
||
|
||
@tasks_bp.route("", methods=["POST"]) | ||
def create_task(): | ||
request_body = request.get_json() | ||
|
||
try: | ||
new_task = Task.from_dict(request_body) | ||
except KeyError as err: | ||
abort(make_response({"details": "Invalid data"}, 400)) | ||
|
||
db.session.add(new_task) | ||
db.session.commit() | ||
|
||
task_message = {} | ||
task_message["task"] = new_task.to_dict() | ||
|
||
return jsonify(task_message), 201 | ||
|
||
|
||
@tasks_bp.route("", methods=["GET"]) | ||
def sort_by_title(): | ||
sort_query = request.args.get("sort") | ||
if sort_query == "asc": | ||
tasks = Task.query.order_by(Task.title) | ||
elif sort_query == "desc": | ||
tasks = Task.query.order_by(Task.title.desc()) | ||
else: | ||
tasks = Task.query.all() | ||
|
||
task_response = [task.to_dict() for task in tasks] | ||
|
||
return jsonify(task_response) | ||
|
||
|
||
@tasks_bp.route("/<task_id>", methods=["GET"]) | ||
def get_one_task(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
task_message = {"task": task.to_dict()} | ||
|
||
return jsonify(task_message) | ||
|
||
|
||
@tasks_bp.route("/<task_id>", methods=["PUT"]) | ||
def update_task(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
request_body = request.get_json() | ||
|
||
task.title = request_body["title"] | ||
task.description = request_body["description"] | ||
|
||
db.session.commit() | ||
|
||
task_message = {"task": task.to_dict()} | ||
|
||
return jsonify(task_message) | ||
|
||
|
||
@tasks_bp.route("/<task_id>", methods=["DELETE"]) | ||
def delete_task(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
db.session.delete(task) | ||
db.session.commit() | ||
|
||
task_message = {"details": f'Task {task.task_id} \"{task.title}\" successfully deleted'} | ||
|
||
return jsonify(task_message) | ||
|
||
|
||
@tasks_bp.route("/<task_id>/mark_complete", methods=["PATCH"]) | ||
def mark_complete(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
try: | ||
task = Task.query.get(task_id) | ||
task.completed_at = datetime.now() | ||
|
||
task_message = {"task": task.to_dict()} | ||
|
||
db.session.commit() | ||
post_to_slack(task) | ||
return make_response(jsonify(task_message), 200) | ||
|
||
except: | ||
abort(make_response({"message": f"{task_id} not found"}, 404)) | ||
|
||
|
||
@tasks_bp.route("/<task_id>/mark_incomplete", methods=["PATCH"]) | ||
def mark_incomplete(task_id): | ||
task = validate_model(Task, task_id) | ||
|
||
try: | ||
task = Task.query.get(task_id) | ||
task.completed_at = None | ||
|
||
db.session.commit() | ||
task_message = {"task": task.to_dict()} | ||
return jsonify(task_message), 200 | ||
|
||
except: | ||
abort(make_response({"message": f"{task_id} not found"}, 404)) | ||
|
||
|
||
def post_to_slack(task): | ||
slack_url = "https://slack.com/api/chat.postMessage" | ||
token = os.environ.get("SLACK_BOT_TOKEN") | ||
headers = {"Authorization": f"Bearer {token}"} | ||
|
||
data = { | ||
"channel": "api-test-channel", | ||
"text": f"Someone just completed the task {task.title}" | ||
} | ||
|
||
response = requests.post(slack_url, headers=headers, data=data) | ||
return response |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Generic single-database configuration. |
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.
This works well and I like the default value approach!